硬汉嵌入式论坛

 找回密码
 立即注册
查看: 6343|回复: 20
收起左侧

[有问必答] STM32F407 RS485高频传输而产生乱码的问题

  [复制链接]

4

主题

18

回帖

30

积分

新手上路

积分
30
发表于 2020-6-5 14:48:27 | 显示全部楼层 |阅读模式
小弟在一项目碰到一难道,RS485每隔5ms向应上位机时,上位机接到的数据是乱码,尝试无数办法,而不得解,特来此宝地,请教各位大佬。

硬件平台:STM32F407ZGT6 + FreeRTOS
硬件接口资源:串口2(RS232)做为调试使用;串口5(RS485)做为读卡器使用;串口6(RS485)做为与上位机通讯使用,RS485全为半双工;
串口驱动:bsp_uart_fifo.c (v1.0 库函数版)
项目功能,单片机读卡,将处理后的卡号数据传送给上位机
工作流程:
STM32F407 串口通讯,波特率38400,通过RS485跟上位机通讯,我的设备做为从机,上位机做为主机,上位机每隔5ms下发一条5字节的指令,要求我在5ms响应,并且在20ms完成传输,需要我上送到上位机的字节数是37字节。
问题现象:
收到上位机指令,然后响应上位机指令,这个过程中上机位收到的数据会有乱码出现。我尝试过使用串口中断接收中断发送;中断接收DMA发送等方式,都还有乱码。使用示波器卡了一下,上位机下发5字节,到STM32F407需要3MS,SMT32F407上送37字节到上位机需要10MS。这跟对方的要求就冲突了。


所有,请教下各位大神,你们有过类似RS485高频传输的经验吗?或者对这种现象,有什么建议?感谢!!!
回复

使用道具 举报

4

主题

18

回帖

30

积分

新手上路

积分
30
 楼主| 发表于 2020-6-5 14:55:23 | 显示全部楼层
另外,在这个贴子 http://armbbs.cn/forum.php?mod=v ... &extra=page%3D1 ,硬汉哥有帮忙看,但是小弟一直没有搞定。。。惭愧。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106726
QQ
发表于 2020-6-5 15:02:59 | 显示全部楼层
方便的话,画个框图。
回复

使用道具 举报

82

主题

401

回帖

667

积分

金牌会员

积分
667
QQ
发表于 2020-6-5 15:19:22 | 显示全部楼层
485通讯加GND了没?
武汉天纵鹏元科技有限公司。承接嵌入式项目开发,相关技术交流。STM32,物联网,工业控制方向。QQ  408137104
回复

使用道具 举报

4

主题

18

回帖

30

积分

新手上路

积分
30
 楼主| 发表于 2020-6-5 15:29:20 | 显示全部楼层
雷鹏 发表于 2020-6-5 15:19
485通讯加GND了没?

485通讯没有接地。
回复

使用道具 举报

4

主题

18

回帖

30

积分

新手上路

积分
30
 楼主| 发表于 2020-6-5 15:51:25 | 显示全部楼层
附件关于处理串口的代码
  1. static void vTaskComm(void *pvParameters)
  2. {
  3.     uint16_t recvLen = 0;
  4.     uint8_t buf[20] = {0};
  5.     uint8_t crc = 0;   

  6.    
  7.     ELEVATOR_BUFF_STRU *sendBuf = &gElevtorData;

  8.     uint8_t defaultBuff[MAX_RS485_LEN+1] ={ 0x5A,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
  9.                                             0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  10.                                             0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  11.                                             0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  12.                                             0x00,0x00,0x00,0x00,0x5A };

  13.     uint32_t i = 0;
  14.    
  15.     READER_BUFF_STRU *ptMsg  = &gReaderMsg;
  16.     BaseType_t xReturn = pdTRUE;/* 定义一个创建信息返回值,默认为pdPASS */
  17.     const TickType_t xMaxBlockTime = pdMS_TO_TICKS(10); /* 设置最大等待时间为200ms */  
  18.    
  19.     //获取当前设备的ID
  20.     uint16_t readID = bsp_dipswitch_read();   

  21.     memset(&gReaderMsg,0x00,sizeof(READER_BUFF_STRU));   

  22.     /* 清零 */
  23.     ptMsg->authMode = 0; //默认为刷卡
  24.     ptMsg->dataLen = 0;
  25.     memset(ptMsg->data,0x00,sizeof(ptMsg->data));

  26.     memset(sendBuf->data,0x00,sizeof(sendBuf->data));   
  27.    
  28.     while (1)
  29.     {  

  30.         memset(buf,0x00,sizeof(buf));        
  31.         recvLen = RS485_Recv(COM6,buf,sizeof(buf));
  32.           if(buf[0] == 0x5A && buf[1] == readID)
  33.           {
  34.                 crc= xorCRC(buf,4);                  
  35.                 if(crc != buf[4])
  36.                 {
  37.                     continue;
  38.                 }

  39.             xReturn = xQueueReceive( xTransDataQueue,    /* 消息队列的句柄 */
  40.                                      (void *)&sendBuf,  /*这里获取的是结构体的地址 */
  41.                                      xMaxBlockTime); /* 设置阻塞时间 */
  42.             if(pdTRUE == xReturn)
  43.             {     
  44.                 printf("2.%02x,%02x\r\n",sendBuf->data[11],sendBuf->data[36]);
  45.             }
  46.             else
  47.             {
  48.                 //发送默认数据包
  49.                 memcpy(sendBuf->data,defaultBuff,MAX_RS485_LEN);
  50.             }

  51.             //BSP_DMAUsart6Puts(sendBuf->data,MAX_RS485_LEN);
  52.             RS485_SendBuf(COM6,sendBuf->data,MAX_RS485_LEN);

  53.         }
  54.         /* 发送事件标志,表示任务正常运行 */        
  55.         xEventGroupSetBits(xCreatedEventGroup, TASK_BIT_1);  
  56.         vTaskDelay(5);
  57.     }
  58. }
复制代码
关于串口部分的代码
  1. /*
  2. *********************************************************************************************************
  3. *
  4. *        模块名称 : 串口中断+FIFO驱动模块
  5. *        文件名称 : bsp_uart_fifo.c
  6. *        版    本 : V1.0
  7. *        说    明 : 采用串口中断+FIFO模式实现多个串口的同时访问
  8. *        修改记录 :
  9. *                版本号  日期       作者    说明
  10. *                V1.0    2013-02-01 armfly  正式发布
  11. *                V1.1    2013-06-09 armfly  FiFo结构增加TxCount成员变量,方便判断缓冲区满; 增加 清FiFo的函数
  12. *                V1.2        2014-09-29 armfly  增加RS485 MODBUS接口。接收到新字节后,直接执行回调函数。
  13. *                V1.3        2015-07-23 armfly  增加 UART_T 结构的读写指针几个成员变量必须增加 __IO 修饰,否则优化后
  14. *                                        会导致串口发送函数死机。
  15. *                V1.4        2015-08-04 armfly  解决UART4配置bug  GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_USART1);
  16. *                V1.5        2015-10-08 armfly  增加修改波特率的接口函数
  17. *
  18. *        Copyright (C), 2015-2020
  19. *
  20. *********************************************************************************************************
  21. */

  22. #include "bsp_uart_fifo.h"
  23. #include "bsp_time.h"
  24. #include "sys.h"




  25. #if 1
  26. #pragma import(__use_no_semihosting)            
  27. //标准库需要的支持函数                 
  28. struct __FILE
  29. {
  30.         int handle;
  31. };

  32. FILE __stdout;      
  33. //定义_sys_exit()以避免使用半主机模式   
  34. void _sys_exit(int x)
  35. {
  36.         x = x;
  37. }

  38. /*
  39. *********************************************************************************************************
  40. *        函 数 名: fputc
  41. *        功能说明: 重定义putc函数,这样可以使用printf函数从串口1打印输出
  42. *        形    参: 无
  43. *        返 回 值: 无
  44. *********************************************************************************************************
  45. */
  46. int fputc(int ch, FILE *f)
  47. {
  48. #if 0        /* 将需要printf的字符通过串口中断FIFO发送出去,printf函数会立即返回 */
  49.         comSendChar(COM1, ch);

  50.         return ch;
  51. #else        /* 采用阻塞方式发送每个字符,等待数据发送完毕 */
  52.         /* 写一个字节到USART1 */
  53.         USART_SendData(USART2, (uint8_t) ch);

  54.         /* 等待发送结束 */
  55.         while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET)
  56.         {}

  57.         return ch;
  58. #endif
  59. }

  60. /*
  61. *********************************************************************************************************
  62. *        函 数 名: fgetc
  63. *        功能说明: 重定义getc函数,这样可以使用getchar函数从串口1输入数据
  64. *        形    参: 无
  65. *        返 回 值: 无
  66. *********************************************************************************************************
  67. */
  68. int fgetc(FILE *f)
  69. {

  70. #if 1        /* 从串口接收FIFO中取1个数据, 只有取到数据才返回 */
  71.         uint8_t ucData;

  72.         while(comGetChar(COM2, &ucData) == 0);

  73.         return ucData;
  74. #else
  75.         /* 等待串口1输入数据 */
  76.         while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);

  77.         return (int)USART_ReceiveData(USART1);
  78. #endif
  79. }

  80. #endif



  81. /* 定义每个串口结构体变量 */
  82. #if UART1_FIFO_EN == 1
  83.         static UART_T g_tUart1;
  84.         static uint8_t g_TxBuf1[UART1_TX_BUF_SIZE];                /* 发送缓冲区 */
  85.         static uint8_t g_RxBuf1[UART1_RX_BUF_SIZE];                /* 接收缓冲区 */
  86. #endif

  87. #if UART2_FIFO_EN == 1
  88.         static UART_T g_tUart2;
  89.         static uint8_t g_TxBuf2[UART2_TX_BUF_SIZE];                /* 发送缓冲区 */
  90.         static uint8_t g_RxBuf2[UART2_RX_BUF_SIZE];                /* 接收缓冲区 */
  91. #endif

  92. #if UART3_FIFO_EN == 1
  93.         static UART_T g_tUart3;
  94.         static uint8_t g_TxBuf3[UART3_TX_BUF_SIZE];                /* 发送缓冲区 */
  95.         static uint8_t g_RxBuf3[UART3_RX_BUF_SIZE];                /* 接收缓冲区 */
  96. #endif

  97. #if UART4_FIFO_EN == 1
  98.         static UART_T g_tUart4;
  99.         static uint8_t g_TxBuf4[UART4_TX_BUF_SIZE];                /* 发送缓冲区 */
  100.         static uint8_t g_RxBuf4[UART4_RX_BUF_SIZE];                /* 接收缓冲区 */
  101. #endif

  102. #if UART5_FIFO_EN == 1
  103.         static UART_T g_tUart5;
  104.         static uint8_t g_TxBuf5[UART5_TX_BUF_SIZE];                /* 发送缓冲区 */
  105.         static uint8_t g_RxBuf5[UART5_RX_BUF_SIZE];                /* 接收缓冲区 */
  106. #endif

  107. #if UART6_FIFO_EN == 1
  108.         static UART_T g_tUart6;
  109.         static uint8_t g_TxBuf6[UART6_TX_BUF_SIZE];                /* 发送缓冲区 */
  110.         static uint8_t g_RxBuf6[UART6_RX_BUF_SIZE];                /* 接收缓冲区 */
  111. #endif

  112. static void UartVarInit(void);
  113. static void InitHardUart(void);
  114. static void UartSend(UART_T *_pUart, uint8_t *_ucaBuf, uint16_t _usLen);
  115. static uint8_t UartGetChar(UART_T *_pUart, uint8_t *_pByte);
  116. static void UartIRQ(UART_T *_pUart);
  117. static void ConfigUartNVIC(void);




  118. /*
  119. *********************************************************************************************************
  120. *        函 数 名: bsp_InitUart
  121. *        功能说明: 初始化串口硬件,并对全局变量赋初值.
  122. *        形    参:  无
  123. *        返 回 值: 无
  124. *********************************************************************************************************
  125. */
  126. void bsp_InitUart(void)
  127. {
  128.         UartVarInit();                /* 必须先初始化全局变量,再配置硬件 */
  129.         InitHardUart();                /* 配置串口的硬件参数(波特率等) */
  130.         RS485_InitTXE();        /* 配置RS485芯片的发送使能硬件,配置为推挽输出 */
  131.         ConfigUartNVIC();        /* 配置串口中断 */
  132. }

  133. /*
  134. *********************************************************************************************************
  135. *        函 数 名: ComToUart
  136. *        功能说明: 将COM端口号转换为UART指针
  137. *        形    参: _ucPort: 端口号(COM1 - COM6)
  138. *        返 回 值: uart指针
  139. *********************************************************************************************************
  140. */
  141. UART_T *ComToUart(COM_PORT_E _ucPort)
  142. {
  143.         if (_ucPort == COM1)
  144.         {
  145.                 #if UART1_FIFO_EN == 1
  146.                         return &g_tUart1;
  147.                 #else
  148.                         return 0;
  149.                 #endif
  150.         }
  151.         else if (_ucPort == COM2)
  152.         {
  153.                 #if UART2_FIFO_EN == 1
  154.                         return &g_tUart2;
  155.                 #else
  156.                         return 0;
  157.                 #endif
  158.         }
  159.         else if (_ucPort == COM3)
  160.         {
  161.                 #if UART3_FIFO_EN == 1
  162.                         return &g_tUart3;
  163.                 #else
  164.                         return 0;
  165.                 #endif
  166.         }
  167.         else if (_ucPort == COM4)
  168.         {
  169.                 #if UART4_FIFO_EN == 1
  170.                         return &g_tUart4;
  171.                 #else
  172.                         return 0;
  173.                 #endif
  174.         }
  175.         else if (_ucPort == COM5)
  176.         {
  177.                 #if UART5_FIFO_EN == 1
  178.                         return &g_tUart5;
  179.                 #else
  180.                         return 0;
  181.                 #endif
  182.         }
  183.         else if (_ucPort == COM6)
  184.         {
  185.                 #if UART6_FIFO_EN == 1
  186.                         return &g_tUart6;
  187.                 #else
  188.                         return 0;
  189.                 #endif
  190.         }
  191.         else
  192.         {
  193.                 /* 不做任何处理 */
  194.                 return 0;
  195.         }
  196. }


  197. /*
  198. *********************************************************************************************************
  199. *        函 数 名: ComToUart
  200. *        功能说明: 将COM端口号转换为 USART_TypeDef* USARTx
  201. *        形    参: _ucPort: 端口号(COM1 - COM6)
  202. *        返 回 值: USART_TypeDef*,  USART1, USART2, USART3, UART4, UART5
  203. *********************************************************************************************************
  204. */
  205. USART_TypeDef *ComToUSARTx(COM_PORT_E _ucPort)
  206. {
  207.         if (_ucPort == COM1)
  208.         {
  209.                 #if UART1_FIFO_EN == 1
  210.                         return USART1;
  211.                 #else
  212.                         return 0;
  213.                 #endif
  214.         }
  215.         else if (_ucPort == COM2)
  216.         {
  217.                 #if UART2_FIFO_EN == 1
  218.                         return USART2;
  219.                 #else
  220.                         return 0;
  221.                 #endif
  222.         }
  223.         else if (_ucPort == COM3)
  224.         {
  225.                 #if UART3_FIFO_EN == 1
  226.                         return USART3;
  227.                 #else
  228.                         return 0;
  229.                 #endif
  230.         }
  231.         else if (_ucPort == COM4)
  232.         {
  233.                 #if UART4_FIFO_EN == 1
  234.                         return UART4;
  235.                 #else
  236.                         return 0;
  237.                 #endif
  238.         }
  239.         else if (_ucPort == COM5)
  240.         {
  241.                 #if UART5_FIFO_EN == 1
  242.                         return UART5;
  243.                 #else
  244.                         return 0;
  245.                 #endif
  246.         }
  247.         else if (_ucPort == COM6)
  248.         {
  249.                 #if UART6_FIFO_EN == 1
  250.                         return USART6;
  251.                 #else
  252.                         return 0;
  253.                 #endif
  254.         }
  255.         else
  256.         {
  257.                 /* 不做任何处理 */
  258.                 return 0;
  259.         }
  260. }

  261. /*
  262. *********************************************************************************************************
  263. *        函 数 名: comSendBuf
  264. *        功能说明: 向串口发送一组数据。数据放到发送缓冲区后立即返回,由中断服务程序在后台完成发送
  265. *        形    参: _ucPort: 端口号(COM1 - COM6)
  266. *                          _ucaBuf: 待发送的数据缓冲区
  267. *                          _usLen : 数据长度
  268. *        返 回 值: 无
  269. *********************************************************************************************************
  270. */
  271. void comSendBuf(COM_PORT_E _ucPort, uint8_t *_ucaBuf, uint16_t _usLen)
  272. {
  273.         UART_T *pUart;

  274.         pUart = ComToUart(_ucPort);
  275.         if (pUart == 0)
  276.         {
  277.                 return;
  278.         }

  279.         if (pUart->SendBefor != 0)
  280.         {
  281.                 pUart->SendBefor();                /* 如果是RS485通信,可以在这个函数中将RS485设置为发送模式 */
  282.         }

  283.         UartSend(pUart, _ucaBuf, _usLen);
  284. }

  285. /*
  286. *********************************************************************************************************
  287. *        函 数 名: comSendChar
  288. *        功能说明: 向串口发送1个字节。数据放到发送缓冲区后立即返回,由中断服务程序在后台完成发送
  289. *        形    参: _ucPort: 端口号(COM1 - COM6)
  290. *                          _ucByte: 待发送的数据
  291. *        返 回 值: 无
  292. *********************************************************************************************************
  293. */
  294. void comSendChar(COM_PORT_E _ucPort, uint8_t _ucByte)
  295. {
  296.         comSendBuf(_ucPort, &_ucByte, 1);
  297. }

  298. /*
  299. *********************************************************************************************************
  300. *        函 数 名: comGetChar
  301. *        功能说明: 从接收缓冲区读取1字节,非阻塞。无论有无数据均立即返回。
  302. *        形    参: _ucPort: 端口号(COM1 - COM5)
  303. *                          _pByte: 接收到的数据存放在这个地址
  304. *        返 回 值: 0 表示无数据, 1 表示读取到有效字节
  305. *********************************************************************************************************
  306. */
  307. uint8_t comGetChar(COM_PORT_E _ucPort, uint8_t *_pByte)
  308. {
  309.         UART_T *pUart;

  310.         pUart = ComToUart(_ucPort);
  311.         if (pUart == 0)
  312.         {
  313.                 return 0;
  314.         }

  315.         return UartGetChar(pUart, _pByte);
  316. }

  317. uint8_t comRecvBuff(COM_PORT_E _ucPort,uint8_t *buf, uint16_t len)
  318. {
  319.     uint8_t i = 0;

  320.     UART_T *pUart;
  321.         pUart = ComToUart(_ucPort);
  322.    
  323.         if (pUart == 0)
  324.         {
  325.                 return 0;
  326.         }
  327.    
  328.     if(len > pUart->usRxCount)  //指定读取长度大于实际接收到的数据长度时
  329.     {
  330.         len=pUart->usRxCount; //读取长度设置为实际接收到的数据长度
  331.     }
  332.    
  333.     for(i=0;i<len;i++)  //拷贝接收到的数据到接收指针中
  334.     {
  335.         UartGetChar(pUart,buf+i);  //将数据复制到buf中
  336.     }

  337.     return len;                   //返回实际读取长度
  338. }


  339. /*
  340. *********************************************************************************************************
  341. *        函 数 名: comClearTxFifo
  342. *        功能说明: 清零串口发送缓冲区
  343. *        形    参: _ucPort: 端口号(COM1 - COM6)
  344. *        返 回 值: 无
  345. *********************************************************************************************************
  346. */
  347. void comClearTxFifo(COM_PORT_E _ucPort)
  348. {
  349.         UART_T *pUart;

  350.         pUart = ComToUart(_ucPort);
  351.         if (pUart == 0)
  352.         {
  353.                 return;
  354.         }

  355.         pUart->usTxWrite = 0;
  356.         pUart->usTxRead = 0;
  357.         pUart->usTxCount = 0;
  358. }

  359. /*
  360. *********************************************************************************************************
  361. *        函 数 名: comClearRxFifo
  362. *        功能说明: 清零串口接收缓冲区
  363. *        形    参: _ucPort: 端口号(COM1 - COM6)
  364. *        返 回 值: 无
  365. *********************************************************************************************************
  366. */
  367. void comClearRxFifo(COM_PORT_E _ucPort)
  368. {
  369.         UART_T *pUart;

  370.         pUart = ComToUart(_ucPort);
  371.         if (pUart == 0)
  372.         {
  373.                 return;
  374.         }

  375.         pUart->usRxWrite = 0;
  376.         pUart->usRxRead = 0;
  377.         pUart->usRxCount = 0;
  378. }

  379. /*
  380. *********************************************************************************************************
  381. *        函 数 名: comSetBaud
  382. *        功能说明: 设置串口的波特率
  383. *        形    参: _ucPort: 端口号(COM1 - COM5)
  384. *                          _BaudRate: 波特率,0-4500000, 最大4.5Mbps
  385. *        返 回 值: 无
  386. *********************************************************************************************************
  387. */
  388. void comSetBaud(COM_PORT_E _ucPort, uint32_t _BaudRate)
  389. {
  390.         USART_TypeDef* USARTx;
  391.        
  392.         USARTx = ComToUSARTx(_ucPort);
  393.         if (USARTx == 0)
  394.         {
  395.                 return;
  396.         }
  397.        
  398.         USART_SetBaudRate(USARTx, _BaudRate);
  399. }

  400. /*
  401. *********************************************************************************************************
  402. *        函 数 名: USART_SetBaudRate
  403. *        功能说明: 修改波特率寄存器,不更改其他设置。如果使用 USART_Init函数, 则会修改硬件流控参数和RX,TX配置
  404. *                          根据固件库中 USART_Init函数,将其中配置波特率的部分单独提出来封装为一个函数
  405. *        形    参: USARTx : USART1, USART2, USART3, UART4, UART5
  406. *                          BaudRate : 波特率,取值 0 - 4500000
  407. *        返 回 值: 无
  408. *********************************************************************************************************
  409. */
  410. void USART_SetBaudRate(USART_TypeDef* USARTx, uint32_t BaudRate)
  411. {
  412.         uint32_t tmpreg = 0x00, apbclock = 0x00;
  413.         uint32_t integerdivider = 0x00;
  414.         uint32_t fractionaldivider = 0x00;
  415.         RCC_ClocksTypeDef RCC_ClocksStatus;

  416.         /* Check the parameters */
  417.         assert_param(IS_USART_ALL_PERIPH(USARTx));
  418.         assert_param(IS_USART_BAUDRATE(BaudRate));  

  419.         /*---------------------------- USART BRR Configuration -----------------------*/
  420.         /* Configure the USART Baud Rate */
  421.         RCC_GetClocksFreq(&RCC_ClocksStatus);

  422.         if ((USARTx == USART1) || (USARTx == USART6))
  423.         {
  424.                 apbclock = RCC_ClocksStatus.PCLK2_Frequency;
  425.         }
  426.         else
  427.         {
  428.                 apbclock = RCC_ClocksStatus.PCLK1_Frequency;
  429.         }

  430.         /* Determine the integer part */
  431.         if ((USARTx->CR1 & USART_CR1_OVER8) != 0)
  432.         {
  433.                 /* Integer part computing in case Oversampling mode is 8 Samples */
  434.                 integerdivider = ((25 * apbclock) / (2 * (BaudRate)));   
  435.         }
  436.         else /* if ((USARTx->CR1 & USART_CR1_OVER8) == 0) */
  437.         {
  438.                 /* Integer part computing in case Oversampling mode is 16 Samples */
  439.                 integerdivider = ((25 * apbclock) / (4 * (BaudRate)));   
  440.         }
  441.         tmpreg = (integerdivider / 100) << 4;

  442.         /* Determine the fractional part */
  443.         fractionaldivider = integerdivider - (100 * (tmpreg >> 4));

  444.         /* Implement the fractional part in the register */
  445.         if ((USARTx->CR1 & USART_CR1_OVER8) != 0)
  446.         {
  447.                 tmpreg |= ((((fractionaldivider * 8) + 50) / 100)) & ((uint8_t)0x07);
  448.         }
  449.         else /* if ((USARTx->CR1 & USART_CR1_OVER8) == 0) */
  450.         {
  451.                 tmpreg |= ((((fractionaldivider * 16) + 50) / 100)) & ((uint8_t)0x0F);
  452.         }

  453.         /* Write to USART BRR register */
  454.         USARTx->BRR = (uint16_t)tmpreg;
  455. }




  456. /* 如果是RS485通信,请按如下格式编写函数*/

  457. /*
  458. *********************************************************************************************************
  459. *        函 数 名: RS485_InitTXE
  460. *        功能说明: 配置RS485发送使能口线 TXE
  461. *        形    参: 无
  462. *        返 回 值: 无
  463. *********************************************************************************************************
  464. */
  465. void RS485_InitTXE(void)
  466. {
  467.    
  468.         GPIO_InitTypeDef GPIO_InitStructure;

  469.     #if UART1_RS485_EN == 1
  470.     #endif

  471.     #if UART2_RS485_EN == 1
  472.     #endif

  473.     #if UART3_RS485_EN == 1

  474.     #endif

  475.     #if UART4_RS485_EN == 1

  476.     #endif   

  477.     #if UART5_RS485_EN == 1
  478.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);        /* 打开GPIO时钟 */
  479.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;                /* 设为输出口 */
  480.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                /* 设为推挽 */
  481.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        /* 无上拉电阻 */
  482.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;        /* IO口最大速度 */
  483.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  484.         GPIO_Init(GPIOD, &GPIO_InitStructure);   
  485.     #endif

  486.     #if UART6_RS485_EN == 1
  487.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);        /* 打开GPIO时钟 */
  488.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;                /* 设为输出口 */
  489.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                /* 设为推挽 */
  490.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        /* 无上拉电阻 */
  491.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;        /* IO口最大速度 */
  492.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  493.         GPIO_Init(GPIOA, &GPIO_InitStructure);      

  494.     #endif   
  495. }

  496. /*
  497. *********************************************************************************************************
  498. *        函 数 名: RS485_SetBaud
  499. *        功能说明: 修改485串口的波特率。
  500. *        形    参: _baud : 波特率.0-4500000
  501. *        返 回 值: 无
  502. *********************************************************************************************************
  503. */
  504. void RS485_SetBaud(COM_PORT_E _ucPort,uint32_t _baud)
  505. {
  506.         comSetBaud(_ucPort, _baud);
  507. }

  508. /*
  509. *********************************************************************************************************
  510. *        函 数 名: RS485_SendBefor
  511. *        功能说明: 发送数据前的准备工作。对于RS485通信,请设置RS485芯片为发送状态,
  512. *                          并修改 UartVarInit()中的函数指针等于本函数名,比如 g_tUart2.SendBefor = RS485_SendBefor
  513. *        形    参: 无
  514. *        返 回 值: 无
  515. *********************************************************************************************************
  516. */
  517. void RS485_SendBefor(void)
  518. {
  519.        
  520.     #if UART1_RS485_EN == 1
  521.     #endif

  522.     #if UART2_RS485_EN == 1
  523.     #endif

  524.     #if UART3_RS485_EN == 1

  525.     #endif

  526.     #if UART4_RS485_EN == 1

  527.     #endif   

  528.     #if UART5_RS485_EN == 1
  529.     RS485_U5_TX_EN();/* 切换RS485收发芯片为发送模式 */
  530.     #endif

  531.     #if UART6_RS485_EN == 1
  532.     RS485_U6_TX_EN();
  533.     #endif        
  534. }

  535. /*
  536. *********************************************************************************************************
  537. *        函 数 名: RS485_SendOver
  538. *        功能说明: 发送一串数据结束后的善后处理。对于RS485通信,请设置RS485芯片为接收状态,
  539. *                          并修改 UartVarInit()中的函数指针等于本函数名,比如 g_tUart2.SendOver = RS485_SendOver
  540. *        形    参: 无
  541. *        返 回 值: 无
  542. *********************************************************************************************************
  543. */
  544. void RS485_SendOver(void)
  545. {
  546.        
  547.     #if UART1_RS485_EN == 1
  548.     #endif

  549.     #if UART2_RS485_EN == 1
  550.     #endif

  551.     #if UART3_RS485_EN == 1

  552.     #endif

  553.     #if UART4_RS485_EN == 1

  554.     #endif   

  555.     #if UART5_RS485_EN == 1
  556.     RS485_U5_RX_EN(); /* 切换RS485收发芯片为接收模式 */
  557.     #endif

  558.     #if UART6_RS485_EN == 1
  559.     RS485_U6_RX_EN();
  560.     #endif   
  561. }


  562. /*
  563. *********************************************************************************************************
  564. *        函 数 名: RS485_SendBuf
  565. *        功能说明: 通过RS485芯片发送一串数据。注意,本函数不等待发送完毕。
  566. *        形    参: _ucaBuf : 数据缓冲区
  567. *                          _usLen : 数据长度
  568. *        返 回 值: 无
  569. *********************************************************************************************************
  570. */
  571. void RS485_SendBuf(COM_PORT_E _ucPort,uint8_t *_ucaBuf, uint16_t _usLen)
  572. {
  573.         comSendBuf(_ucPort, _ucaBuf, _usLen);
  574. }


  575. /*
  576. *********************************************************************************************************
  577. *        函 数 名: RS485_SendStr
  578. *        功能说明: 向485总线发送一个字符串,0结束。
  579. *        形    参: _pBuf 字符串,0结束
  580. *        返 回 值: 无
  581. *********************************************************************************************************
  582. */
  583. void RS485_SendStr(COM_PORT_E _ucPort,char *_pBuf)
  584. {
  585.         RS485_SendBuf(_ucPort,(uint8_t *)_pBuf, strlen(_pBuf));
  586. }

  587. /*
  588. *********************************************************************************************************
  589. *        函 数 名: RS485_ReciveNew
  590. *        功能说明: 接收到新的数据
  591. *        形    参: _byte 接收到的新数据
  592. *        返 回 值: 无
  593. *********************************************************************************************************
  594. */
  595. //extern void MODBUS_ReciveNew(uint8_t _byte);
  596. void RS485_ReciveNew(uint8_t _byte)
  597. {
  598. //        MODBUS_ReciveNew(_byte);
  599. }

  600. uint16_t RS485_Recv(COM_PORT_E _ucPort,uint8_t *buf, uint16_t len)
  601. {
  602.     uint16_t i = 0;

  603.     UART_T *pUart;
  604.         pUart = ComToUart(_ucPort);
  605.    
  606.         if (pUart == 0)
  607.         {
  608.                 return 0;
  609.         }
  610.    
  611.     if(len > pUart->usRxCount)  //指定读取长度大于实际接收到的数据长度时
  612.     {
  613.         len=pUart->usRxCount; //读取长度设置为实际接收到的数据长度
  614.     }
  615.    
  616.     for(i=0;i<len;i++)  //拷贝接收到的数据到接收指针中
  617.     {
  618.         UartGetChar(pUart,buf+i);  //将数据复制到buf中
  619.     }

  620.     return len;                   //返回实际读取长度
  621. }


  622. uint16_t RS485_RecvAtTime(COM_PORT_E _ucPort,uint8_t *buf, uint16_t len,uint32_t timeout)
  623. {
  624.     //uint8_t i = 0;   
  625.     uint16_t recvSize = len;
  626.     uint16_t recvLen = 0;
  627.     //uint8_t tmp[1] = {0};
  628.     UART_T *pUart;
  629.         pUart = ComToUart(_ucPort);
  630.    
  631.         if (pUart == 0)
  632.         {
  633.                 return 0;
  634.         }
  635.    
  636.     if(recvSize > pUart->usRxCount)  //指定读取长度大于实际接收到的数据长度时
  637.     {
  638.         recvSize=pUart->usRxCount; //读取长度设置为实际接收到的数据长度
  639.     }  


  640.         g500usTimerRS485 = timeout;

  641.         while (1)
  642.         {
  643.                 if (g500usTimerRS485 == 0) return recvLen;


  644.         UartGetChar(pUart,buf + recvLen);
  645.         recvLen++;

  646.                 if (recvLen >= recvSize) return recvSize;
  647.         }  

  648. }



  649. /*
  650. *********************************************************************************************************
  651. *        函 数 名: UartVarInit
  652. *        功能说明: 初始化串口相关的变量
  653. *        形    参: 无
  654. *        返 回 值: 无
  655. *********************************************************************************************************
  656. */
  657. static void UartVarInit(void)
  658. {
  659. #if UART1_FIFO_EN == 1
  660.         g_tUart1.uart = USART1;                                                /* STM32 串口设备 */
  661.         g_tUart1.pTxBuf = g_TxBuf1;                                        /* 发送缓冲区指针 */
  662.         g_tUart1.pRxBuf = g_RxBuf1;                                        /* 接收缓冲区指针 */
  663.         g_tUart1.usTxBufSize = UART1_TX_BUF_SIZE;        /* 发送缓冲区大小 */
  664.         g_tUart1.usRxBufSize = UART1_RX_BUF_SIZE;        /* 接收缓冲区大小 */
  665.         g_tUart1.usTxWrite = 0;                                                /* 发送FIFO写索引 */
  666.         g_tUart1.usTxRead = 0;                                                /* 发送FIFO读索引 */
  667.         g_tUart1.usRxWrite = 0;                                                /* 接收FIFO写索引 */
  668.         g_tUart1.usRxRead = 0;                                                /* 接收FIFO读索引 */
  669.         g_tUart1.usRxCount = 0;                                                /* 接收到的新数据个数 */
  670.         g_tUart1.usTxCount = 0;                                                /* 待发送的数据个数 */
  671.         g_tUart1.SendBefor = 0;                                                /* 发送数据前的回调函数 */
  672.         g_tUart1.SendOver = 0;                                                /* 发送完毕后的回调函数 */
  673.         g_tUart1.ReciveNew = 0;                                                /* 接收到新数据后的回调函数 */
  674. #endif

  675. #if UART2_FIFO_EN == 1
  676.         g_tUart2.uart = USART2;                                                /* STM32 串口设备 */
  677.         g_tUart2.pTxBuf = g_TxBuf2;                                        /* 发送缓冲区指针 */
  678.         g_tUart2.pRxBuf = g_RxBuf2;                                        /* 接收缓冲区指针 */
  679.         g_tUart2.usTxBufSize = UART2_TX_BUF_SIZE;        /* 发送缓冲区大小 */
  680.         g_tUart2.usRxBufSize = UART2_RX_BUF_SIZE;        /* 接收缓冲区大小 */
  681.         g_tUart2.usTxWrite = 0;                                                /* 发送FIFO写索引 */
  682.         g_tUart2.usTxRead = 0;                                                /* 发送FIFO读索引 */
  683.         g_tUart2.usRxWrite = 0;                                                /* 接收FIFO写索引 */
  684.         g_tUart2.usRxRead = 0;                                                /* 接收FIFO读索引 */
  685.         g_tUart2.usRxCount = 0;                                                /* 接收到的新数据个数 */
  686.         g_tUart2.usTxCount = 0;                                                /* 待发送的数据个数 */
  687.         g_tUart2.SendBefor = 0;                /* 发送数据前的回调函数 */
  688.         g_tUart2.SendOver = 0;                        /* 发送完毕后的回调函数 */
  689.         g_tUart2.ReciveNew = 0;                /* 接收到新数据后的回调函数 */
  690. #endif

  691. #if UART3_FIFO_EN == 1
  692.         g_tUart3.uart = USART3;                                                /* STM32 串口设备 */
  693.         g_tUart3.pTxBuf = g_TxBuf3;                                        /* 发送缓冲区指针 */
  694.         g_tUart3.pRxBuf = g_RxBuf3;                                        /* 接收缓冲区指针 */
  695.         g_tUart3.usTxBufSize = UART3_TX_BUF_SIZE;        /* 发送缓冲区大小 */
  696.         g_tUart3.usRxBufSize = UART3_RX_BUF_SIZE;        /* 接收缓冲区大小 */
  697.         g_tUart3.usTxWrite = 0;                                                /* 发送FIFO写索引 */
  698.         g_tUart3.usTxRead = 0;                                                /* 发送FIFO读索引 */
  699.         g_tUart3.usRxWrite = 0;                                                /* 接收FIFO写索引 */
  700.         g_tUart3.usRxRead = 0;                                                /* 接收FIFO读索引 */
  701.         g_tUart3.usRxCount = 0;                                                /* 接收到的新数据个数 */
  702.         g_tUart3.usTxCount = 0;                                                /* 待发送的数据个数 */
  703.         g_tUart3.SendBefor = 0;                                /* 发送数据前的回调函数 */
  704.         g_tUart3.SendOver = 0;                                    /* 发送完毕后的回调函数 */
  705.         g_tUart3.ReciveNew = 0;                                /* 接收到新数据后的回调函数 */
  706. #endif

  707. #if UART4_FIFO_EN == 1
  708.         g_tUart4.uart = UART4;                                                /* STM32 串口设备 */
  709.         g_tUart4.pTxBuf = g_TxBuf4;                                        /* 发送缓冲区指针 */
  710.         g_tUart4.pRxBuf = g_RxBuf4;                                        /* 接收缓冲区指针 */
  711.         g_tUart4.usTxBufSize = UART4_TX_BUF_SIZE;        /* 发送缓冲区大小 */
  712.         g_tUart4.usRxBufSize = UART4_RX_BUF_SIZE;        /* 接收缓冲区大小 */
  713.         g_tUart4.usTxWrite = 0;                                                /* 发送FIFO写索引 */
  714.         g_tUart4.usTxRead = 0;                                                /* 发送FIFO读索引 */
  715.         g_tUart4.usRxWrite = 0;                                                /* 接收FIFO写索引 */
  716.         g_tUart4.usRxRead = 0;                                                /* 接收FIFO读索引 */
  717.         g_tUart4.usRxCount = 0;                                                /* 接收到的新数据个数 */
  718.         g_tUart4.usTxCount = 0;                                                /* 待发送的数据个数 */
  719.         g_tUart4.SendBefor = 0;                                                /* 发送数据前的回调函数 */
  720.         g_tUart4.SendOver = 0;                                                /* 发送完毕后的回调函数 */
  721.         g_tUart4.ReciveNew = 0;                                                /* 接收到新数据后的回调函数 */
  722. #endif

  723. #if UART5_FIFO_EN == 1
  724.         g_tUart5.uart = UART5;                                                /* STM32 串口设备 */
  725.         g_tUart5.pTxBuf = g_TxBuf5;                                        /* 发送缓冲区指针 */
  726.         g_tUart5.pRxBuf = g_RxBuf5;                                        /* 接收缓冲区指针 */
  727.         g_tUart5.usTxBufSize = UART5_TX_BUF_SIZE;        /* 发送缓冲区大小 */
  728.         g_tUart5.usRxBufSize = UART5_RX_BUF_SIZE;        /* 接收缓冲区大小 */
  729.         g_tUart5.usTxWrite = 0;                                                /* 发送FIFO写索引 */
  730.         g_tUart5.usTxRead = 0;                                                /* 发送FIFO读索引 */
  731.         g_tUart5.usRxWrite = 0;                                                /* 接收FIFO写索引 */
  732.         g_tUart5.usRxRead = 0;                                                /* 接收FIFO读索引 */
  733.         g_tUart5.usRxCount = 0;                                                /* 接收到的新数据个数 */
  734.         g_tUart5.usTxCount = 0;                                                /* 待发送的数据个数 */
  735.         g_tUart5.SendBefor = RS485_SendBefor;                                                /* 发送数据前的回调函数 */
  736.         g_tUart5.SendOver = RS485_SendOver;                                                /* 发送完毕后的回调函数 */
  737.         g_tUart5.ReciveNew = RS485_ReciveNew;                                                /* 接收到新数据后的回调函数 */
  738. #endif


  739. #if UART6_FIFO_EN == 1
  740.         g_tUart6.uart = USART6;                                                /* STM32 串口设备 */
  741.         g_tUart6.pTxBuf = g_TxBuf6;                                        /* 发送缓冲区指针 */
  742.         g_tUart6.pRxBuf = g_RxBuf6;                                        /* 接收缓冲区指针 */
  743.         g_tUart6.usTxBufSize = UART6_TX_BUF_SIZE;        /* 发送缓冲区大小 */
  744.         g_tUart6.usRxBufSize = UART6_RX_BUF_SIZE;        /* 接收缓冲区大小 */
  745.         g_tUart6.usTxWrite = 0;                                                /* 发送FIFO写索引 */
  746.         g_tUart6.usTxRead = 0;                                                /* 发送FIFO读索引 */
  747.         g_tUart6.usRxWrite = 0;                                                /* 接收FIFO写索引 */
  748.         g_tUart6.usRxRead = 0;                                                /* 接收FIFO读索引 */
  749.         g_tUart6.usRxCount = 0;                                                /* 接收到的新数据个数 */
  750.         g_tUart6.usTxCount = 0;                                                /* 待发送的数据个数 */
  751.         g_tUart6.SendBefor = RS485_SendBefor;                                                /* 发送数据前的回调函数 */
  752.         g_tUart6.SendOver = RS485_SendOver;                                                /* 发送完毕后的回调函数 */
  753.         g_tUart6.ReciveNew = RS485_ReciveNew;                                                /* 接收到新数据后的回调函数 */
  754. #endif
  755. }

  756. /*
  757. *********************************************************************************************************
  758. *        函 数 名: InitHardUart
  759. *        功能说明: 配置串口的硬件参数(波特率,数据位,停止位,起始位,校验位,中断使能)适合于STM32-F4开发板
  760. *        形    参: 无
  761. *        返 回 值: 无
  762. *********************************************************************************************************
  763. */
  764. static void InitHardUart(void)
  765. {
  766.         GPIO_InitTypeDef GPIO_InitStructure;
  767.         USART_InitTypeDef USART_InitStructure;

  768. #if UART1_FIFO_EN == 1                /* 串口1 TX = PA9   RX = PA10 或 TX = PB6   RX = PB7*/

  769.         /* 第1步: 配置GPIO */
  770.         #if 1        /* TX = PA9   RX = PA10 */
  771.                 /* 打开 GPIO 时钟 */
  772.                 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

  773.                 /* 打开 UART 时钟 */
  774.                 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

  775.                 /* 将 PA9 映射为 USART1_TX */
  776.                 GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);

  777.                 /* 将 PA10 映射为 USART1_RX */
  778.                 GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);

  779.                 /* 配置 USART Tx 为复用功能 */
  780.                 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;        /* 输出类型为推挽 */
  781.                 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        /* 内部上拉电阻使能 */
  782.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        /* 复用模式 */

  783.                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  784.                 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  785.                 GPIO_Init(GPIOA, &GPIO_InitStructure);

  786.                 /* 配置 USART Rx 为复用功能 */
  787.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  788.                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  789.                 GPIO_Init(GPIOA, &GPIO_InitStructure);
  790.         #else        /* TX = PB6   RX = PB7  */
  791.                 /* 打开 GPIO 时钟 */
  792.                 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

  793.                 /* 打开 UART 时钟 */
  794.                 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

  795.                 /* 将 PB6 映射为 USART1_TX */
  796.                 GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1);

  797.                 /* 将 PB7 映射为 USART1_RX */
  798.                 GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);

  799.                 /* 配置 USART Tx 为复用功能 */
  800.                 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;        /* 输出类型为推挽 */
  801.                 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        /* 内部上拉电阻使能 */
  802.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        /* 复用模式 */

  803.                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  804.                 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  805.                 GPIO_Init(GPIOB, &GPIO_InitStructure);

  806.                 /* 配置 USART Rx 为复用功能 */
  807.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  808.                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  809.                 GPIO_Init(GPIOB, &GPIO_InitStructure);
  810.         #endif

  811.         /* 第2步: 配置串口硬件参数 */
  812.         USART_InitStructure.USART_BaudRate = UART1_BAUD;        /* 波特率 */
  813.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  814.         USART_InitStructure.USART_StopBits = USART_StopBits_1;
  815.         USART_InitStructure.USART_Parity = USART_Parity_No ;
  816.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  817.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  818.         USART_Init(USART1, &USART_InitStructure);

  819.         USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);        /* 使能接收中断 */
  820.         /*
  821.                 USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
  822.                 注意: 不要在此处打开发送中断
  823.                 发送中断使能在SendUart()函数打开
  824.         */
  825.         USART_Cmd(USART1, ENABLE);                /* 使能串口 */

  826.         /* CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去
  827.                 如下语句解决第1个字节无法正确发送出去的问题 */
  828.         USART_ClearFlag(USART1, USART_FLAG_TC);     /* 清发送完成标志,Transmission Complete flag */
  829. #endif

  830. #if UART2_FIFO_EN == 1                /* 串口2 TX = PD5   RX = PD6 或  TX = PA2, RX = PA3  */
  831.         /* 第1步: 配置GPIO */
  832.         #if 1        /* 串口2 TX = PD5   RX = PD6 */
  833.                 /* 打开 GPIO 时钟 */
  834.                 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

  835.                 /* 打开 UART 时钟 */
  836.                 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

  837.                 /* 将 PD5 映射为 USART2_TX */
  838.                 GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_USART2);

  839.                 /* 将 PD6 映射为 USART2_RX */
  840.                 GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_USART2);

  841.                 /* 配置 USART Tx 为复用功能 */
  842.                 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;        /* 输出类型为推挽 */
  843.                 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        /* 内部上拉电阻使能 */
  844.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        /* 复用模式 */

  845.                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  846.                 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  847.                 GPIO_Init(GPIOD, &GPIO_InitStructure);

  848.                 /* 配置 USART Rx 为复用功能 */
  849.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  850.                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  851.                 GPIO_Init(GPIOD, &GPIO_InitStructure);

  852.         #else        /* 串口2   TX = PA2, RX = PA3 */
  853.                 /* 打开 GPIO 时钟 */
  854.                 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

  855.                 /* 打开 UART 时钟 */
  856.                 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

  857.                 /* 将 PA2 映射为 USART2_TX. 在STM32-V5板中,PA2 管脚用于以太网 */
  858.                 //GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);

  859.                 /* 将 PA3 映射为 USART2_RX */
  860.                 GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);

  861.                 /* 配置 USART Tx 为复用功能 */
  862.                 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;        /* 输出类型为推挽 */
  863.                 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        /* 内部上拉电阻使能 */
  864.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        /* 复用模式 */

  865.                 //GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  866.                 //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  867.                 //GPIO_Init(GPIOA, &GPIO_InitStructure);

  868.                 /* 配置 USART Rx 为复用功能 */
  869.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  870.                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  871.                 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  872.                 GPIO_Init(GPIOA, &GPIO_InitStructure);
  873.         #endif

  874.         /* 第2步: 配置串口硬件参数 */
  875.         USART_InitStructure.USART_BaudRate = UART2_BAUD;        /* 波特率 */
  876.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  877.         USART_InitStructure.USART_StopBits = USART_StopBits_1;
  878.         USART_InitStructure.USART_Parity = USART_Parity_No ;
  879.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  880.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                /* 选择发接收模式 */
  881.         USART_Init(USART2, &USART_InitStructure);

  882.         USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);        /* 使能接收中断 */
  883.         /*
  884.                 USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
  885.                 注意: 不要在此处打开发送中断
  886.                 发送中断使能在SendUart()函数打开
  887.         */
  888.         USART_Cmd(USART2, ENABLE);                /* 使能串口 */

  889.         /* CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去
  890.                 如下语句解决第1个字节无法正确发送出去的问题 */
  891.         USART_ClearFlag(USART2, USART_FLAG_TC);     /* 清发送完成标志,Transmission Complete flag */
  892. #endif

  893. #if UART3_FIFO_EN == 1                       
  894.     #if 0   /* 串口3 TX = PB10   RX = PB11 */
  895.         /* 打开 GPIO 时钟 */
  896.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

  897.         /* 打开 UART 时钟 */
  898.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);

  899.         /* 将 PB10 映射为 USART3_TX */
  900.         GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3);

  901.         /* 将 PB11 映射为 USART3_RX */
  902.         GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3);

  903.         /* 配置 USART Tx 为复用功能 */
  904.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;        /* 输出类型为推挽 */
  905.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        /* 内部上拉电阻使能 */
  906.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        /* 复用模式 */

  907.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  908.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  909.         GPIO_Init(GPIOB, &GPIO_InitStructure);

  910.         /* 配置 USART Rx 为复用功能 */
  911.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  912.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  913.         GPIO_Init(GPIOB, &GPIO_InitStructure);

  914.     #else
  915.         /* 打开 GPIO 时钟 */
  916.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

  917.         /* 打开 UART 时钟 */
  918.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);

  919.         /* 将 PD8 映射为 USART3_TX */
  920.         GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_USART3);

  921.         /* 将 PD9 映射为 USART3_RX */
  922.         GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_USART3);

  923.         /* 配置 USART Tx 为复用功能 */
  924.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;        /* 输出类型为推挽 */
  925.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        /* 内部上拉电阻使能 */
  926.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        /* 复用模式 */

  927.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  928.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  929.         GPIO_Init(GPIOD, &GPIO_InitStructure);

  930.         /* 配置 USART Rx 为复用功能 */
  931.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  932.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  933.         GPIO_Init(GPIOD, &GPIO_InitStructure);

  934.     #endif

  935.         /* 第2步: 配置串口硬件参数 */
  936.         USART_InitStructure.USART_BaudRate = UART3_BAUD;        /* 波特率 */
  937.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  938.         USART_InitStructure.USART_StopBits = USART_StopBits_1;
  939.         USART_InitStructure.USART_Parity = USART_Parity_No ;
  940.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  941.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  942.         USART_Init(USART3, &USART_InitStructure);

  943.         USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);        /* 使能接收中断 */
  944.         /*
  945.                 USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
  946.                 注意: 不要在此处打开发送中断
  947.                 发送中断使能在SendUart()函数打开
  948.         */
  949.         USART_Cmd(USART3, ENABLE);                /* 使能串口 */

  950.         /* CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去
  951.                 如下语句解决第1个字节无法正确发送出去的问题 */
  952.         USART_ClearFlag(USART3, USART_FLAG_TC);     /* 清发送完成标志,Transmission Complete flag */   
  953. #endif

  954. #if UART4_FIFO_EN == 1                        /* 串口4 TX = PC10   RX = PC11 */
  955.         /* 第1步: 配置GPIO */

  956.         /* 打开 GPIO 时钟 */
  957.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);

  958.         /* 打开 UART 时钟 */
  959.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);

  960.         /* 将 PC10 映射为 UART4_TX */
  961.         GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_UART4);

  962.         /* 将 PC11 映射为 UART4_RX */
  963.         GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_UART4);

  964.         /* 配置 USART Tx 为复用功能 */
  965.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;        /* 输出类型为推挽 */
  966.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        /* 内部上拉电阻使能 */
  967.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        /* 复用模式 */

  968.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  969.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  970.         GPIO_Init(GPIOC, &GPIO_InitStructure);

  971.         /* 配置 USART Rx 为复用功能 */
  972.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  973.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  974.         GPIO_Init(GPIOC, &GPIO_InitStructure);

  975.         /* 第2步: 配置串口硬件参数 */
  976.         USART_InitStructure.USART_BaudRate = UART4_BAUD;        /* 波特率 */
  977.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  978.         USART_InitStructure.USART_StopBits = USART_StopBits_1;
  979.         USART_InitStructure.USART_Parity = USART_Parity_No ;
  980.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  981.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  982.         USART_Init(UART4, &USART_InitStructure);

  983.         USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);        /* 使能接收中断 */
  984.         /*
  985.                 USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
  986.                 注意: 不要在此处打开发送中断
  987.                 发送中断使能在SendUart()函数打开
  988.         */
  989.         USART_Cmd(UART4, ENABLE);                /* 使能串口 */

  990.         /* CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去
  991.                 如下语句解决第1个字节无法正确发送出去的问题 */
  992.         USART_ClearFlag(UART4, USART_FLAG_TC);     /* 清发送完成标志,Transmission Complete flag */
  993. #endif

  994. #if UART5_FIFO_EN == 1                        /* 串口5 TX = PC12   RX = PD2 */
  995.         /* 第1步: 配置GPIO */

  996.         /* 打开 GPIO 时钟 */
  997.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC |RCC_AHB1Periph_GPIOD, ENABLE);

  998.         /* 打开 UART 时钟 */
  999.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);

  1000.         /* 将 PC12 映射为 UART5_TX */
  1001.         GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_UART5);

  1002.         /* 将 PD2 映射为 UART5_RX */
  1003.         GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_UART5);

  1004.         /* 配置 UART Tx 为复用功能 */
  1005.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;        /* 输出类型为推挽 */
  1006.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        /* 内部上拉电阻使能 */
  1007.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        /* 复用模式 */

  1008.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
  1009.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  1010.         GPIO_Init(GPIOC, &GPIO_InitStructure);

  1011.         /* 配置 UART Rx 为复用功能 */
  1012.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  1013.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  1014.         GPIO_Init(GPIOD, &GPIO_InitStructure);

  1015.         /* 第2步: 配置串口硬件参数 */
  1016.         USART_InitStructure.USART_BaudRate = UART5_BAUD;        /* 波特率 */
  1017.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  1018.         USART_InitStructure.USART_StopBits = USART_StopBits_1;
  1019.         USART_InitStructure.USART_Parity = USART_Parity_No ;
  1020.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  1021.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  1022.         USART_Init(UART5, &USART_InitStructure);

  1023.         USART_ITConfig(UART5, USART_IT_RXNE, ENABLE);        /* 使能接收中断 */
  1024.         /*
  1025.                 USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
  1026.                 注意: 不要在此处打开发送中断
  1027.                 发送中断使能在SendUart()函数打开
  1028.         */
  1029.         USART_Cmd(UART5, ENABLE);                /* 使能串口 */

  1030.         /* CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去
  1031.                 如下语句解决第1个字节无法正确发送出去的问题 */
  1032.         USART_ClearFlag(UART5, USART_FLAG_TC);     /* 清发送完成标志,Transmission Complete flag */
  1033. #endif

  1034. #if UART6_FIFO_EN == 1                        /* PG14/USART6_TX , PC7/USART6_RX,PG8/USART6_RTS, PG15/USART6_CTS */
  1035.         /* 第1步: 配置GPIO */

  1036.         /* 打开 GPIO 时钟 */
  1037.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);

  1038.         /* 打开 UART 时钟 */
  1039.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE);

  1040.         /* 将 PC6 映射为 USART6_TX */
  1041.         GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_USART6);

  1042.         /* 将 PC7 映射为 USART6_RX */
  1043.         GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_USART6);


  1044.         /* 配置 PG14/USART6_TX 为复用功能 */
  1045.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;        /* 输出类型为推挽 */
  1046.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        /* 内部上拉电阻使能 */
  1047.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        /* 复用模式 */

  1048.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  1049.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  1050.         GPIO_Init(GPIOC, &GPIO_InitStructure);

  1051.         /* 配置 PC7/USART6_RX 为复用功能 */
  1052.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  1053.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  1054.         GPIO_Init(GPIOC, &GPIO_InitStructure);


  1055.         /* 第2步: 配置串口硬件参数 */
  1056.         USART_InitStructure.USART_BaudRate = UART6_BAUD;        /* 波特率 */
  1057.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  1058.         USART_InitStructure.USART_StopBits = USART_StopBits_1;
  1059.         USART_InitStructure.USART_Parity = USART_Parity_No ;
  1060.         //USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_RTS_CTS;        /* 选择硬件流控 */
  1061.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;        /* 不要硬件流控 */
  1062.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  1063.         USART_Init(USART6, &USART_InitStructure);

  1064.         USART_ITConfig(USART6, USART_IT_RXNE, ENABLE);        /* 使能接收中断 */
  1065.         /*
  1066.                 USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
  1067.                 注意: 不要在此处打开发送中断
  1068.                 发送中断使能在SendUart()函数打开
  1069.         */
  1070.         USART_Cmd(USART6, ENABLE);                /* 使能串口 */

  1071.         /* CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去
  1072.                 如下语句解决第1个字节无法正确发送出去的问题 */
  1073.         USART_ClearFlag(USART6, USART_FLAG_TC);     /* 清发送完成标志,Transmission Complete flag */
  1074. #endif
  1075. }

  1076. /*
  1077. *********************************************************************************************************
  1078. *        函 数 名: ConfigUartNVIC
  1079. *        功能说明: 配置串口硬件中断.
  1080. *        形    参:  无
  1081. *        返 回 值: 无
  1082. *********************************************************************************************************
  1083. */
  1084. static void ConfigUartNVIC(void)
  1085. {
  1086.         NVIC_InitTypeDef NVIC_InitStructure;

  1087.         /* Configure the NVIC Preemption Priority Bits */
  1088.         /*        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);  --- 在 bsp.c 中 bsp_Init() 中配置中断优先级组 */

  1089. #if UART1_FIFO_EN == 1
  1090.         /* 使能串口1中断 */
  1091.         NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  1092.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  1093.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  1094.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  1095.         NVIC_Init(&NVIC_InitStructure);
  1096. #endif

  1097. #if UART2_FIFO_EN == 1
  1098.         /* 使能串口2中断 */
  1099.         NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
  1100.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 5;
  1101.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  1102.         NVIC_Init(&NVIC_InitStructure);
  1103. #endif

  1104. #if UART3_FIFO_EN == 1
  1105.         /* 使能串口3中断t */
  1106.         NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
  1107.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  1108.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  1109.         NVIC_Init(&NVIC_InitStructure);
  1110. #endif

  1111. #if UART4_FIFO_EN == 1
  1112.         /* 使能串口4中断t */
  1113.         NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
  1114.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  1115.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  1116.         NVIC_Init(&NVIC_InitStructure);
  1117. #endif

  1118. #if UART5_FIFO_EN == 1
  1119.         /* 使能串口5中断t */
  1120.         NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn;
  1121.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
  1122.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  1123.         NVIC_Init(&NVIC_InitStructure);
  1124. #endif

  1125. #if UART6_FIFO_EN == 1
  1126.         /* 使能串口6中断t */
  1127.         NVIC_InitStructure.NVIC_IRQChannel = USART6_IRQn;
  1128.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4;
  1129.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  1130.         NVIC_Init(&NVIC_InitStructure);
  1131. #endif
  1132. }

  1133. /*
  1134. *********************************************************************************************************
  1135. *        函 数 名: UartSend
  1136. *        功能说明: 填写数据到UART发送缓冲区,并启动发送中断。中断处理函数发送完毕后,自动关闭发送中断
  1137. *        形    参:  无
  1138. *        返 回 值: 无
  1139. *********************************************************************************************************
  1140. */
  1141. static void UartSend(UART_T *_pUart, uint8_t *_ucaBuf, uint16_t _usLen)
  1142. {
  1143.         uint16_t i;
  1144.    

  1145.         for (i = 0; i < _usLen; i++)
  1146.         {
  1147.                 /* 如果发送缓冲区已经满了,则等待缓冲区空 */

  1148.                 /* 当 _pUart->usTxBufSize == 1 时, 下面的函数会死掉(待完善) */
  1149.                 while (1)
  1150.                 {
  1151.                         __IO uint16_t usCount;
  1152. //                        DISABLE_INT();
  1153.                         usCount = _pUart->usTxCount;
  1154. //                        ENABLE_INT();

  1155.                         if (usCount < _pUart->usTxBufSize)
  1156.                         {
  1157.                                 break;
  1158.                         }
  1159.             else if(usCount == _pUart->usTxBufSize)/* 数据已填满缓冲区 */
  1160.                         {
  1161.                                 if((_pUart->uart->CR1 & USART_CR1_TXEIE) == 0)
  1162.                                 {
  1163.                                         SET_BIT(_pUart->uart->CR1, USART_CR1_TXEIE);
  1164.                                 }  
  1165.                         }
  1166.                 }
  1167.        

  1168.                 /* 将新数据填入发送缓冲区 */
  1169.                 _pUart->pTxBuf[_pUart->usTxWrite] = _ucaBuf[i];

  1170. //                DISABLE_INT();
  1171.                 if (++_pUart->usTxWrite >= _pUart->usTxBufSize)
  1172.                 {
  1173.                         _pUart->usTxWrite = 0;
  1174.                 }
  1175.                 _pUart->usTxCount++;
  1176. //                ENABLE_INT();
  1177.         }

  1178.         USART_ITConfig(_pUart->uart, USART_IT_TXE, ENABLE);
  1179. }

  1180. /*
  1181. *********************************************************************************************************
  1182. *        函 数 名: UartGetChar
  1183. *        功能说明: 从串口接收缓冲区读取1字节数据 (用于主程序调用)
  1184. *        形    参: _pUart : 串口设备
  1185. *                          _pByte : 存放读取数据的指针
  1186. *        返 回 值: 0 表示无数据  1表示读取到数据
  1187. *********************************************************************************************************
  1188. */
  1189. static uint8_t UartGetChar(UART_T *_pUart, uint8_t *_pByte)
  1190. {
  1191.         uint16_t usCount;

  1192.         /* usRxWrite 变量在中断函数中被改写,主程序读取该变量时,必须进行临界区保护 */
  1193. //        DISABLE_INT();
  1194.         usCount = _pUart->usRxCount;
  1195. //        ENABLE_INT();

  1196.         /* 如果读和写索引相同,则返回0 */
  1197.         //if (_pUart->usRxRead == usRxWrite)
  1198.         if (usCount == 0)        /* 已经没有数据 */
  1199.         {
  1200.                 return 0;
  1201.         }
  1202.         else
  1203.         {
  1204.                 *_pByte = _pUart->pRxBuf[_pUart->usRxRead];                /* 从串口接收FIFO取1个数据 */

  1205.                 /* 改写FIFO读索引 */
  1206. //                DISABLE_INT();
  1207.                 if (++_pUart->usRxRead >= _pUart->usRxBufSize)
  1208.                 {
  1209.                         _pUart->usRxRead = 0;
  1210.                 }
  1211.                 _pUart->usRxCount--;
  1212. //                ENABLE_INT();
  1213.                 return 1;
  1214.         }
  1215. }

  1216. /*
  1217. *********************************************************************************************************
  1218. *        函 数 名: comGetBuff
  1219. *        功能说明: 读取指字长度的字符
  1220. *        形    参: _ucPort: 端口号(COM1 - COM5)
  1221. *                          Buff: 接收到的数据存放在这个地址
  1222.              len:要读取的字符长度
  1223. *        返 回 值: 0 读取失败; 非零为读取到的数据长度
  1224. *********************************************************************************************************
  1225. */
  1226. uint16_t comGetBuff(COM_PORT_E _ucPort,uint8_t *Buff, uint16_t RecvSize,uint16_t timeout_MilliSeconds)
  1227. {

  1228. //        uint16_t RecvLen = 0;
  1229. //        uint8_t ch[1] = {0};

  1230. //        if (len == 0 || Buff == NULL) return 0;

  1231. //        while (len--)
  1232. //        {
  1233. //                if (comGetChar (_ucPort,ch) == 1)
  1234. //                {
  1235. //                        Buff[RecvLen++] = ch[0];
  1236. //            printf("push : %d\r\n",RecvLen);
  1237. //                }

  1238. //                if (RecvLen >= len) return RecvLen;
  1239. //        }

  1240. //        return RecvLen;


  1241.         uint16_t RecvLen = 0;
  1242.         uint8_t tmp[1] = {0};

  1243.         if (RecvSize == 0) return 0;

  1244.         g500usTimerUART = timeout_MilliSeconds;

  1245.         while (1)
  1246.         {
  1247.                 if (g500usTimerUART == 0) return RecvLen;

  1248.                 if (comGetChar (_ucPort,tmp) == 1)
  1249.                 {
  1250.                         Buff[RecvLen++] = tmp[0];
  1251.                 }

  1252.                 if (RecvLen >= RecvSize) return RecvLen;
  1253.         }

  1254. }



  1255. /*
  1256. *********************************************************************************************************
  1257. *        函 数 名: UartIRQ
  1258. *        功能说明: 供中断服务程序调用,通用串口中断处理函数
  1259. *        形    参: _pUart : 串口设备
  1260. *        返 回 值: 无
  1261. *********************************************************************************************************
  1262. */
  1263. static void UartIRQ(UART_T *_pUart)
  1264. {
  1265.     uint32_t ulReturn;
  1266.     /* 进入临界段,临界段可以嵌套 */
  1267.     ulReturn = taskENTER_CRITICAL_FROM_ISR();
  1268.    

  1269.         /* 处理接收中断  */
  1270.         if (USART_GetITStatus(_pUart->uart, USART_IT_RXNE) != RESET)
  1271.         {
  1272.                 /* 从串口接收数据寄存器读取数据存放到接收FIFO */
  1273.                 uint8_t ch;

  1274.                 ch = USART_ReceiveData(_pUart->uart);
  1275.                 _pUart->pRxBuf[_pUart->usRxWrite] = ch;
  1276.                 if (++_pUart->usRxWrite >= _pUart->usRxBufSize)
  1277.                 {
  1278.                         _pUart->usRxWrite = 0;
  1279.                 }
  1280.         
  1281.                 if (_pUart->usRxCount < _pUart->usRxBufSize)
  1282.                 {
  1283.                         _pUart->usRxCount++;
  1284.                 }

  1285.                 /* 回调函数,通知应用程序收到新数据,一般是发送1个消息或者设置一个标记 */
  1286.                 //if (_pUart->usRxWrite == _pUart->usRxRead)
  1287.                 //if (_pUart->usRxCount == 1)
  1288.                 {
  1289.                         if (_pUart->ReciveNew)
  1290.                         {
  1291.                                 _pUart->ReciveNew(ch);
  1292.                         }
  1293.                 }
  1294.         }

  1295.         /* 处理发送缓冲区空中断 */
  1296.         if (USART_GetITStatus(_pUart->uart, USART_IT_TXE) != RESET)
  1297.         {
  1298.                 //if (_pUart->usTxRead == _pUart->usTxWrite)
  1299.                 if (_pUart->usTxCount == 0)
  1300.                 {
  1301.                         /* 发送缓冲区的数据已取完时, 禁止发送缓冲区空中断 (注意:此时最后1个数据还未真正发送完毕)*/
  1302.                         USART_ITConfig(_pUart->uart, USART_IT_TXE, DISABLE);

  1303.                         /* 使能数据发送完毕中断 */
  1304.                         USART_ITConfig(_pUart->uart, USART_IT_TC, ENABLE);
  1305.                 }
  1306.                 else
  1307.                 {
  1308.                         /* 从发送FIFO取1个字节写入串口发送数据寄存器 */
  1309.                         USART_SendData(_pUart->uart, _pUart->pTxBuf[_pUart->usTxRead]);
  1310.                         if (++_pUart->usTxRead >= _pUart->usTxBufSize)
  1311.                         {
  1312.                                 _pUart->usTxRead = 0;
  1313.                         }
  1314.                         _pUart->usTxCount--;
  1315.                 }

  1316.         }
  1317.         /* 数据bit位全部发送完毕的中断 */
  1318.         else if (USART_GetITStatus(_pUart->uart, USART_IT_TC) != RESET)
  1319.         {
  1320.                 //if (_pUart->usTxRead == _pUart->usTxWrite)
  1321.                 if (_pUart->usTxCount == 0)
  1322.                 {
  1323.                         /* 如果发送FIFO的数据全部发送完毕,禁止数据发送完毕中断 */
  1324.                         USART_ITConfig(_pUart->uart, USART_IT_TC, DISABLE);

  1325.                         /* 回调函数, 一般用来处理RS485通信,将RS485芯片设置为接收模式,避免抢占总线 */
  1326.                         if (_pUart->SendOver)
  1327.                         {
  1328.                                 _pUart->SendOver();
  1329.                         }
  1330.                 }
  1331.                 else
  1332.                 {
  1333.                         /* 正常情况下,不会进入此分支 */

  1334.                         /* 如果发送FIFO的数据还未完毕,则从发送FIFO取1个数据写入发送数据寄存器 */
  1335.                         USART_SendData(_pUart->uart, _pUart->pTxBuf[_pUart->usTxRead]);
  1336.                         if (++_pUart->usTxRead >= _pUart->usTxBufSize)
  1337.                         {
  1338.                                 _pUart->usTxRead = 0;
  1339.                         }
  1340.                         _pUart->usTxCount--;
  1341.                 }
  1342.         }

  1343.   /* 退出临界段 */
  1344.   taskEXIT_CRITICAL_FROM_ISR( ulReturn );       
  1345. }

  1346. /*
  1347. *********************************************************************************************************
  1348. *        函 数 名: USART1_IRQHandler  USART2_IRQHandler USART3_IRQHandler UART4_IRQHandler UART5_IRQHandler
  1349. *        功能说明: USART中断服务程序
  1350. *        形    参: 无
  1351. *        返 回 值: 无
  1352. *********************************************************************************************************
  1353. */
  1354. #if UART1_FIFO_EN == 1
  1355. void USART1_IRQHandler(void)
  1356. {
  1357.         UartIRQ(&g_tUart1);
  1358. }
  1359. #endif

  1360. #if UART2_FIFO_EN == 1
  1361. void USART2_IRQHandler(void)
  1362. {
  1363.         UartIRQ(&g_tUart2);
  1364. }
  1365. #endif

  1366. #if UART3_FIFO_EN == 1
  1367. void USART3_IRQHandler(void)
  1368. {
  1369.         UartIRQ(&g_tUart3);
  1370. }
  1371. #endif

  1372. #if UART4_FIFO_EN == 1
  1373. void UART4_IRQHandler(void)
  1374. {
  1375.         UartIRQ(&g_tUart4);
  1376. }
  1377. #endif

  1378. #if UART5_FIFO_EN == 1
  1379. void UART5_IRQHandler(void)
  1380. {
  1381.         UartIRQ(&g_tUart5);
  1382. }
  1383. #endif

  1384. #if UART6_FIFO_EN == 1
  1385. void USART6_IRQHandler(void)
  1386. {
  1387.         UartIRQ(&g_tUart6);
  1388. }
  1389. #endif






  1390. void RS485_U6_RX_EN(void)
  1391. {
  1392.     int i=0;

  1393.     for(i=0;i<500;i++)
  1394.     {
  1395.         ;
  1396.     }
  1397. //     GPIOA->BSRRH = GPIO_Pin_8;
  1398.      GPIO_ResetBits(GPIOA,GPIO_Pin_8);
  1399.     for(i=0;i<500;i++)
  1400.     {
  1401.         ;
  1402.     }
  1403. }

  1404. void RS485_U6_TX_EN(void)
  1405. {
  1406.     int i=0;

  1407.     for(i=0;i<500;i++)
  1408.     {
  1409.         ;
  1410.     }
  1411. //     GPIOA->BSRRL = GPIO_Pin_8;
  1412.     GPIO_SetBits(GPIOA,GPIO_Pin_8);

  1413.     for(i=0;i<500;i++)
  1414.     {
  1415.         ;
  1416.     }

  1417. }





复制代码





串口数据处理流程

串口数据处理流程
回复

使用道具 举报

334

主题

2032

回帖

3039

积分

版主

Rank: 7Rank: 7Rank: 7

积分
3039
发表于 2020-6-5 15:59:35 | 显示全部楼层
简单计算一下,38400波特率,一般单字节需要9个位,那么1ms可以发送4.2个字节。 那么指令5个字节,耗时约1.2ms;37个回答字节耗时约8.7ms。
所以客户要求有点紧张,但是可以达到。 所以,你的F407查询间隔必须小于5ms,采用串口DMA发送。 接收也使用DMA+串口空闲中断即可。
回复

使用道具 举报

82

主题

401

回帖

667

积分

金牌会员

积分
667
QQ
发表于 2020-6-5 16:03:45 | 显示全部楼层
surge 发表于 2020-6-5 15:29
485通讯没有接地。

加根地线试试。
武汉天纵鹏元科技有限公司。承接嵌入式项目开发,相关技术交流。STM32,物联网,工业控制方向。QQ  408137104
回复

使用道具 举报

5

主题

61

回帖

76

积分

初级会员

积分
76
发表于 2020-6-5 16:08:43 | 显示全部楼层
波特率38400  上位机下发5字节,到STM32F407需要3MS,我怎么觉得你这句话有问题5个字节无校验位50个bit   1/38400x50(bit)大约1.3ms   有点矛盾啊!
回复

使用道具 举报

4

主题

18

回帖

30

积分

新手上路

积分
30
 楼主| 发表于 2020-6-5 16:08:47 | 显示全部楼层
caicaptain2 发表于 2020-6-5 15:59
简单计算一下,38400波特率,一般单字节需要9个位,那么1ms可以发送4.2个字节。 那么指令5个字节,耗时约1. ...

我也按您说的这个方法尝试过,串口空闲中断+DMA发送,结果依然不好。附件RS485 空闲中断+DMA发送的代码

  1. #include "bsp_usart6.h"
  2. #include "FreeRTOS.h"
  3. #include "task.h"


  4. #define COM6_RXBUFFER_SIZE   255 //串口接收缓存器长度
  5. #define UART6_RX_LEN         COM6_RXBUFFER_SIZE //USART1 DMA接收缓存器长度
  6. #define UART6_TX_LEN         COM6_RXBUFFER_SIZE //USART1 DMA发送缓存器长度

  7. typedef struct COMx_RXBUFFER
  8. {
  9.     u8 buffer[COM6_RXBUFFER_SIZE];//接收缓存器
  10.     u8 RxFlag;//接收数据标志 1:接收到新数据 0:无新数据被接收
  11.     u16 RxLen;//接收到数据长度
  12. }COMx_RXBUFFER;

  13. //串口1接收DMA缓存
  14. COMx_RXBUFFER Uart6_RxBuffer;


  15. uint8_t Uart6_Tx[UART6_TX_LEN] = {0};               //串口1发送DMA缓存     
  16. uint8_t Uart6_Rx[UART6_RX_LEN] = {0};               //串口1接收DMA缓存

  17. static void BSP_DMAUsar6Rx_Init(void);
  18. static void BSP_DMAUsar6Tx_Init(void);


  19. void bsp_Usart6_Init (uint32_t BaudRate)
  20. {
  21.     //GPIO端口设置
  22.         GPIO_InitTypeDef GPIO_InitStructure;
  23.         USART_InitTypeDef USART_InitStructure;
  24.         NVIC_InitTypeDef NVIC_InitStructure;

  25.         RCC_AHB1PeriphClockCmd(USART1_GPIO_CLK,ENABLE); //使能GPIOA时钟
  26.         RCC_APB2PeriphClockCmd(USART1_CLK,ENABLE);//使能USART1时钟

  27.         //串口1对应引脚复用映射
  28.         GPIO_PinAFConfig(USART1_GPIO_PORT,USART1_TX_SOURCE,USART1_TX_AF); //GPIOA9复用为USART1
  29.         GPIO_PinAFConfig(USART1_GPIO_PORT,USART1_RX_SOURCE,USART1_RX_AF); //GPIOA10复用为USART1
  30.        
  31.         //USART1端口配置
  32.         GPIO_InitStructure.GPIO_Pin = USART1_TX_PIN | USART1_RX_PIN; //GPIOA9与GPIOA10
  33.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
  34.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;        //速度50MHz
  35.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
  36.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
  37.         GPIO_Init(USART1_GPIO_PORT,&GPIO_InitStructure); //初始化PA9,PA10

  38.     //DE1
  39.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);        /* 打开GPIO时钟 */
  40.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;                /* 设为输出口 */
  41.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                /* 设为推挽 */
  42.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        /* 无上拉电阻 */
  43.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;        /* IO口最大速度 */
  44.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  45.         GPIO_Init(GPIOA, &GPIO_InitStructure);                  

  46.    //USART1 初始化设置
  47.         USART_InitStructure.USART_BaudRate = BaudRate;//波特率设置
  48.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
  49.         USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
  50.         USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
  51.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
  52.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        //收发模式
  53.         USART_Init(USART6, &USART_InitStructure); //初始化串口1   


  54.     //开启USART6
  55.     USART_Cmd(USART6, ENABLE);
  56.    

  57.         USART_ClearFlag(USART6, USART_FLAG_TC); //清除发送完成标志       
  58.         while(USART_GetFlagStatus(USART6, USART_FLAG_TC) == RESET);        //等待空闲帧发送完成后再清零发送完成标志
  59.         USART_ClearFlag(USART6, USART_FLAG_TC);        //清除发送完成标志
  60.    
  61.     //开启USART6总线空闲中断
  62.         USART_ITConfig(USART6,USART_IT_TC,DISABLE);  
  63.         USART_ITConfig(USART6,USART_IT_RXNE,DISABLE);
  64.         USART_ITConfig(USART6,USART_IT_TXE,DISABLE);
  65.         USART_ITConfig(USART6,USART_IT_IDLE,ENABLE);



  66.         //Usart1 NVIC 配置
  67.         NVIC_InitStructure.NVIC_IRQChannel = USART6_IRQn;//串口1中断通道
  68.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级1
  69.         NVIC_InitStructure.NVIC_IRQChannelSubPriority =4;                //子优先级1
  70.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
  71.         NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器


  72.        
  73.     //串口接收DMA配置
  74.     BSP_DMAUsar6Rx_Init();
  75.     //串口发送DMA配置
  76.     BSP_DMAUsar6Tx_Init();

  77.     USART_DMACmd(USART6,USART_DMAReq_Tx,ENABLE);  //采用DMA方式发送   
  78.     USART_DMACmd(USART6,USART_DMAReq_Rx,ENABLE); //采用DMA方式接收

  79. }

  80. void USART6_IRQHandler(void)
  81. {   
  82.     int i = 0;
  83.     uint32_t ulReturn;
  84.     /* 进入临界段,临界段可以嵌套 */
  85.     ulReturn = taskENTER_CRITICAL_FROM_ISR();
  86.    
  87.     if(USART_GetITStatus(USART6, USART_IT_IDLE) != RESET)  
  88.     {
  89.       //1.清除USART6接收完成中断
  90.         USART6->SR;  
  91.         USART6->DR;   //清USART_IT_IDLE标志  
  92.       //2.存储收到的数据内容、长度、标志位
  93.         DMA_Cmd(DMA2_Stream1,DISABLE); //使能数据流1 通道5
  94.         
  95.         DMA_ClearFlag(DMA2_Stream1, DMA_FLAG_TCIF1 | DMA_FLAG_FEIF1 | DMA_FLAG_DMEIF1 | DMA_FLAG_TEIF1 | DMA_FLAG_HTIF1);//清零标志位
  96.    
  97.         Uart6_RxBuffer.RxLen = UART6_RX_LEN - DMA_GetCurrDataCounter(DMA2_Stream1);        //计算接收数据包长度      
  98.       
  99.         for (i = 0;i <  Uart6_RxBuffer.RxLen;i++)    //将接收到的数据包缓存
  100.         {  
  101.             Uart6_RxBuffer.buffer[i] = Uart6_Rx[i];               
  102.         }       

  103.         if(Uart6_RxBuffer.RxLen <= UART6_RX_LEN)
  104.         {
  105.             //printf(">>>>>>>>>>>>>>>>>>>>>>>>>>\r\n");
  106.         }

  107.         DMA_SetCurrDataCounter(DMA2_Stream1,UART6_RX_LEN);                      //设置传输数据长度
  108.         DMA_Cmd(DMA2_Stream1,ENABLE);                                           //打开DMA
  109.     }

  110.     if(USART_GetITStatus(USART6, USART_IT_TC) != RESET)
  111.     {
  112.         USART_ClearFlag(USART6,USART_IT_TC);
  113.         
  114.         //关闭发送完成中断
  115.         USART_ITConfig(USART6,USART_IT_TC,DISABLE);
  116.         
  117.         RS485_U6_RX_EN();
  118.     }

  119.   /* 退出临界段 */
  120.   taskEXIT_CRITICAL_FROM_ISR( ulReturn );            

  121. }

  122. //USART1接收DMA配置
  123. static void BSP_DMAUsar6Rx_Init(void)
  124. {
  125.     DMA_InitTypeDef   DMA_InitStructure;
  126.     u16 mid_u16RetryCnt = 0;
  127.    
  128.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);                        //启动DMA时钟  
  129.    
  130.     DMA_DeInit(DMA2_Stream1);
  131.     while ((DMA_GetCmdStatus(DMA2_Stream1) != DISABLE) && (mid_u16RetryCnt++ < 500));
  132.    
  133.     DMA_InitStructure.DMA_Channel = DMA_Channel_5;
  134.     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART6->DR);         //外设地址      
  135.     DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Uart6_Rx;                 //内存地址      
  136.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;                     //dma传输方向单向      
  137.     DMA_InitStructure.DMA_BufferSize = UART6_RX_LEN;                            //设置DMA在传输时缓冲区的长度     
  138.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;            //设置DMA的外设递增模式,一个外设        
  139.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                     //设置DMA的内存递增模式      
  140.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;     //外设数据字长         
  141.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;             //内存数据字长      
  142.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                               //设置DMA的传输模式      
  143.     DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;                     //设置DMA的优先级别     
  144.    
  145.         DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
  146.         DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  147.         DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  148.         DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  149.    
  150.     DMA_Init(DMA2_Stream1,&DMA_InitStructure);          
  151.     DMA_Cmd(DMA2_Stream1,ENABLE);                                               //使能数据流1 通道5
  152. }

  153. //USART6发送DMA配置
  154. static void BSP_DMAUsar6Tx_Init(void)
  155. {
  156.     DMA_InitTypeDef   DMA_InitStructure;  
  157.     NVIC_InitTypeDef NVIC_InitStructure;
  158.     u16 mid_u16RetryCnt = 0;
  159.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);                        //启动DMA时钟  
  160.    
  161.     DMA_DeInit(DMA2_Stream6);
  162.     while ((DMA_GetCmdStatus(DMA2_Stream6) != DISABLE) && (mid_u16RetryCnt++ < 500));
  163.    
  164.     DMA_InitStructure.DMA_Channel = DMA_Channel_5;
  165.         DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART6->DR);         //DMA外设基地址
  166.         DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Uart6_Tx;                 //DMA内存基地址
  167.         DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                     //数据传输方向,从内存读取发送到外设
  168.         DMA_InitStructure.DMA_BufferSize = UART6_TX_LEN;                            //DMA通道的DMA缓存的大小
  169.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;            //外设地址寄存器不变
  170.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                     //内存地址寄存器递增
  171.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;     //数据宽度为8位
  172.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;             //数据宽度为8位
  173.         DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                               //工作在正常模式
  174.         DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                       //DMA通道 x拥有中优先级
  175.    
  176.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
  177.           DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  178.           DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  179.           DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;   
  180.        


  181.     //DMA发送中断设置
  182.     NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream6_IRQn;
  183.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  184.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  185.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  186.     NVIC_Init(&NVIC_InitStructure);
  187.     DMA_ITConfig(DMA2_Stream6,DMA_IT_TC,ENABLE);   
  188.    
  189.         DMA_Init(DMA2_Stream6, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART6_Tx_DMA_Channel所标识的寄存器   
  190.     DMA_Cmd(DMA2_Stream6,DISABLE);
  191. }
  192. //USART2 DMA发送指定长度的数据
  193. //str:要发送的数据首地址
  194. //cndtr:数据传输量
  195. void BSP_DMAUsart6Puts(unsigned char *str,u8 cndtr)
  196. {
  197.     u16 l_u16RetryCnt = 0;   
  198.     RS485_U6_TX_EN();
  199.     memcpy(Uart6_Tx, str, cndtr);
  200.     DMA_Cmd(DMA2_Stream6, DISABLE);                      //关闭DMA传输           
  201.     while ((DMA_GetCmdStatus(DMA2_Stream6) != DISABLE) && (l_u16RetryCnt++ < 500));        //等待DMA可配置       
  202.     DMA_SetCurrDataCounter(DMA2_Stream6, cndtr);  //数据传输量          
  203.     DMA_Cmd(DMA2_Stream6, ENABLE);                              //开启DMA传输           
  204. }

  205. //DMA2中断函数。
  206. void DMA2_Stream6_IRQHandler(void)
  207. {

  208.     if(DMA_GetFlagStatus(DMA2_Stream6, DMA_FLAG_TCIF6) != RESET)        //DMA发送完成  
  209.     {   
  210.                 DMA_ClearFlag(DMA2_Stream6, DMA_FLAG_TCIF6 | DMA_FLAG_FEIF6 |
  211.                                           DMA_FLAG_DMEIF6 | DMA_FLAG_TEIF6 | DMA_FLAG_HTIF6);         //清除标志位                       
  212.                
  213.                 while(!USART_GetFlagStatus(USART6, USART_FLAG_TC));        //等待USART1发送完成标志TC置1
  214.                 USART_ClearFlag(USART6, USART_FLAG_TC);         //清除发送完成标志

  215.                 DMA_Cmd(DMA2_Stream6,DISABLE);
  216.         USART_ITConfig(USART6,USART_IT_TC,ENABLE);                 
  217.                 RS485_U6_RX_EN();                //切换为RS485接收模式               
  218.     }

  219. }



复制代码


回复

使用道具 举报

5

主题

61

回帖

76

积分

初级会员

积分
76
发表于 2020-6-5 16:24:36 | 显示全部楼层
从机回复37个字节    1/38400x370(bit) = 9.6ms     主机5ms 下发5个字节,这个方案是不行的  
提高波特率     或者更改主机下发命令间隔时间     再或者 改为 RS422 全双工   
回复

使用道具 举报

4

主题

18

回帖

30

积分

新手上路

积分
30
 楼主| 发表于 2020-6-5 16:32:23 | 显示全部楼层
dghwjh 发表于 2020-6-5 16:24
从机回复37个字节    1/38400x370(bit) = 9.6ms     主机5ms 下发5个字节,这个方案是不行的  
提高波特率 ...

上位机是电梯,电梯公司不会理我的,波特率,时间都定死的,顶天我这边改为全双工的RS485.
回复

使用道具 举报

73

主题

1193

回帖

1412

积分

至尊会员

积分
1412
发表于 2020-6-5 17:29:02 | 显示全部楼层
surge 发表于 2020-6-5 16:32
上位机是电梯,电梯公司不会理我的,波特率,时间都定死的,顶天我这边改为全双工的RS485.

就这个霸王公司有点恶心
回复

使用道具 举报

4

主题

18

回帖

30

积分

新手上路

积分
30
 楼主| 发表于 2020-6-6 08:22:56 | 显示全部楼层
雷鹏 发表于 2020-6-5 16:03
加根地线试试。

我本地加地线没用吧?上位机那边只预留了两条线。
回复

使用道具 举报

19

主题

371

回帖

428

积分

高级会员

积分
428
发表于 2020-6-6 20:13:26 | 显示全部楼层
建议先用纯中断处理,如成功,再用DMA
回复

使用道具 举报

2

主题

39

回帖

45

积分

新手上路

积分
45
发表于 2020-6-7 13:45:37 | 显示全部楼层
上位机5ms间隔下发,你必须在5ms内处理完数据并且发送完毕,不然5ms一到上位机又开始下发了,你还没有上传完成,那么肯定会出问题的。38400传输37个字节,8N1的情况下,37*9/38400=需要9ms,所以我觉得就是设计有问题,现在的情况下你下位机怎么改都有问题。
回复

使用道具 举报

16

主题

203

回帖

251

积分

高级会员

积分
251
发表于 2020-6-8 10:15:07 | 显示全部楼层
落叶凋零 发表于 2020-6-7 13:45
上位机5ms间隔下发,你必须在5ms内处理完数据并且发送完毕,不然5ms一到上位机又开始下发了,你还没有上传 ...

485的硬件接口部分没有看到,不好说具体是哪里的问题,我这边测试过1M传输都没有问题
回复

使用道具 举报

334

主题

2032

回帖

3039

积分

版主

Rank: 7Rank: 7Rank: 7

积分
3039
发表于 2020-6-8 11:32:51 | 显示全部楼层
本帖最后由 caicaptain2 于 2020-6-8 11:34 编辑
yjwpm 发表于 2020-6-8 10:15
485的硬件接口部分没有看到,不好说具体是哪里的问题,我这边测试过1M传输都没有问题

赞同。。。几百米的距离, 485传输1Mb都是没有问题的。 记得用双绞线。

另外,你这个时间要求也是应该没有问题的。 记得设定modbus任务的优先级高一点。  1ms的响应速度,对于F4来说,很容易的。
建议,首先用示波器观察波形,确定硬件方便的问题。 传输时间,应该和理论一样才对。
回复

使用道具 举报

4

主题

18

回帖

30

积分

新手上路

积分
30
 楼主| 发表于 2020-6-14 08:05:43 | 显示全部楼层
感谢各位大佬的帮忙,我更改了指令解析那块的内容,把延时时间改为绝对延时,每2ms去读一下接收缓冲区,然后解析指令,电梯每5ms一次查询指令,在5ms内接收到第一个字节后,20ms后传完,就OK了。附上指令解析部分的代码
  1. static uint8_t deal_Serial_Parse(void)
  2. {
  3.     uint8_t ch = 0;
  4.    
  5.     while(RS485_Recv(COM6,&ch,1))
  6.     {
  7.        switch (rxFromHost.rxStatus)
  8.         {               
  9.             case STEP1:
  10.                 if(0x5A == ch) /*接收包头*/
  11.                 {
  12.                     rxFromHost.rxBuff[0] = ch;
  13.                     rxFromHost.rxCRC = ch;
  14.                     rxFromHost.rxCnt = 1;
  15.                     rxFromHost.rxStatus = STEP2;
  16.                 }

  17.                 break;
  18.            case STEP2:
  19.                 if(0x01 == ch) //判定第二个字节是否是需要的字节,若多梯联动时需读取拨码开关的值
  20.                 {
  21.                     rxFromHost.rxBuff[1] = ch;
  22.                     rxFromHost.rxCRC ^= ch;
  23.                     rxFromHost.rxCnt = 2;
  24.                     rxFromHost.rxStatus = STEP3;               
  25.                 }
  26.                 else
  27.                 {
  28.                
  29.                    memset(&rxFromHost,0x00,sizeof(rxFromHost));                  
  30.                 }
  31.                 break;           
  32.             default:      /* 接收整个数据包 */
  33.             
  34.                 rxFromHost.rxBuff[rxFromHost.rxCnt++] = ch;
  35.                 rxFromHost.rxCRC ^= ch;
  36.                
  37.                 if(rxFromHost.rxCnt >= 5)
  38.                 {
  39.                
  40.                     if(rxFromHost.rxCRC == 0)
  41.                     {
  42.                         memset(&rxFromHost,0x00,sizeof(rxFromHost));
  43.                         return FINISHED;                        
  44.                     }  
  45.                     memset(&rxFromHost,0x00,sizeof(rxFromHost));
  46.                 }
  47.             
  48.                 break;
  49.          }
  50.          
  51.     }   

  52.     return UNFINISHED;
  53. }
复制代码


回复

使用道具 举报

4

主题

74

回帖

86

积分

初级会员

积分
86
发表于 2023-9-6 16:09:31 | 显示全部楼层
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-2 03:51 , Processed in 0.389079 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表