小车通过PG8和PG14和鲁班猫通信,对应的就是USART5串口
企业微信截图_16988262273589.png

USART5串口实现

usart5_rt.h

  1. #ifndef UART5_RT_H
  2. #define UART5_RT_H
  3. #include "gd32f4xx.h"
  4. #include "systick.h"
  5. #include "stdio.h"
  6. #include "string.h"
  7. extern float speed[3];
  8. //RX和TX引脚时钟
  9. #define USART_TX_RX_RCU RCU_GPIOG
  10. //USART0时钟
  11. #define USART_RCU RCU_USART5
  12. //引脚类型
  13. #define USART_GPIO GPIOG
  14. //引脚编号
  15. #define USART_RX_PIN GPIO_PIN_9
  16. #define USART_TX_PIN GPIO_PIN_14
  17. //复用编号
  18. #define RX_ALT_NUM GPIO_AF_8
  19. #define TX_ALT_NUM GPIO_AF_8
  20. //USART编号
  21. #define USART_NUM USART5
  22. //USART中断配置
  23. #define NVIC_IRQ USART5_IRQn
  24. //USART0的DMA时钟
  25. #define BSP_DMA_RCU RCU_DMA1
  26. #define BSP_DMA DMA1
  27. #define BSP_DMA_CHANNEL_RX DMA_CH1
  28. #define BSP_DMA_CHANNEL_TX DMA_CH6
  29. //DMA外部连接
  30. #define RX_DMA_SUBPERIPHERAL_ENUM DMA_SUBPERI5
  31. #define TX_DMA_SUBPERIPHERAL_ENUM DMA_SUBPERI5
  32. //USART关于GPIO配置
  33. void usart5_gpio_config(void);
  34. //USART关于参数配置
  35. void usart5_param_config(uint32_t baudval);
  36. //DMA发送配置
  37. int32_t usart5_dma_tx_init(uint32_t periph_addr);
  38. //USART接收的dma配置
  39. int32_t usart5_dma_rx_init(uint32_t periph_addr);
  40. //包含gpio和usart参数配置
  41. void usart5_dma_config(uint32_t baudval);
  42. //通过DMA发送
  43. int32_t uart5_dma_send(uint8_t *data,uint32_t len);
  44. //解析速度
  45. void parse_speed(void);
  46. #endif

usart5_rt.c

  1. #include "uart5_rt.h"
  2. //uint8_t g_send_data[256];//发送数据
  3. uint8_t temp5[1] = {0};
  4. //接收数据最终存放位置
  5. uint8_t g5_recv_data[256];//接收数据
  6. //x y及z的线速度
  7. float speed[3] = {0.0};
  8. void usart5_gpio_config(void){
  9. // ● 开启时钟(包括串口时钟和GPIO时钟)
  10. rcu_periph_clock_enable(USART_TX_RX_RCU);
  11. rcu_periph_clock_enable(USART_RCU);
  12. // ● 配置GPIO复用模式
  13. gpio_af_set(USART_GPIO,RX_ALT_NUM,USART_RX_PIN);
  14. gpio_af_set(USART_GPIO,TX_ALT_NUM,USART_TX_PIN);
  15. // ● 配置GPIO的模式
  16. gpio_mode_set(USART_GPIO,GPIO_MODE_AF,GPIO_PUPD_PULLUP,USART_RX_PIN);
  17. gpio_mode_set(USART_GPIO,GPIO_MODE_AF,GPIO_PUPD_PULLUP,USART_TX_PIN);
  18. // ● 配置GPIO的输出
  19. /* 配置TX为推挽输出 50MHZ */
  20. gpio_output_options_set(USART_GPIO, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, USART_RX_PIN);
  21. /* 配置RX为推挽输出 50MHZ */
  22. gpio_output_options_set(USART_GPIO, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, USART_TX_PIN);
  23. }
  24. void usart5_param_config(uint32_t baudval){
  25. //USART复位
  26. usart_deinit(USART_NUM);
  27. //波特率
  28. usart_baudrate_set(USART_NUM,baudval);
  29. //校验位
  30. usart_parity_config(USART_NUM,USART_PM_NONE);
  31. //一个周期发送的数据位数
  32. usart_word_length_set(USART_NUM,USART_WL_8BIT);
  33. //停止位
  34. usart_stop_bit_set(USART_NUM,USART_STB_1BIT);
  35. //先发送高位还是低位
  36. usart_data_first_config(USART_NUM,USART_MSBF_LSB);
  37. //串口使能
  38. usart_enable(USART_NUM);
  39. //发送功能配置
  40. usart_transmit_config(USART_NUM,USART_TRANSMIT_ENABLE);
  41. //接收配置
  42. usart_receive_config(USART_NUM,USART_RECEIVE_ENABLE);
  43. //接收中断配置
  44. nvic_irq_enable(NVIC_IRQ, 2, 2);
  45. //配置处理哪些中断
  46. //USART_INT_RBNE:接收到一个字符就会触发,需要保存接收的字符
  47. usart_interrupt_enable(USART_NUM, USART_INT_RBNE); // 读数据缓冲区非空中断和过载错误中断
  48. //USART_INT_IDLE:一帧数据接收完成 hello 可以打印对应的字符串
  49. usart_interrupt_enable(USART_NUM, USART_INT_IDLE); // DLE线检测中断
  50. /* 使能串口DMA发送 */
  51. usart_dma_transmit_config(USART_NUM, USART_TRANSMIT_DMA_ENABLE);
  52. /* 使能串口DMA接收 */
  53. usart_dma_receive_config(USART_NUM, USART_RECEIVE_DMA_ENABLE);
  54. //接收中断配置
  55. nvic_irq_enable(NVIC_IRQ, 2, 2);
  56. //USART_INT_IDLE:一帧数据接收完成 hello 可以打印对应的字符串
  57. usart_interrupt_enable(USART_NUM, USART_INT_IDLE); // DLE线检测中断
  58. }
  59. int32_t usart5_dma_tx_init(uint32_t periph_addr)
  60. {
  61. /* 使能DMA时钟 */
  62. rcu_periph_clock_enable(BSP_DMA_RCU);
  63. /* 复位DMA并禁用DMA传输 */
  64. dma_deinit(BSP_DMA, BSP_DMA_CHANNEL_TX);
  65. /* 配置DMA传输结构体 */
  66. dma_single_data_parameter_struct dma_init_struct;
  67. //DMA传输方向:从内存到外设
  68. dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
  69. //传输数据的内存地址
  70. // dma_init_struct.memory0_addr = (uint32_t)g_send_data;
  71. //内存地址递增
  72. dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
  73. //传输数据的大小
  74. // dma_init_struct.number = sizeof(g_send_data);
  75. //外设地址
  76. dma_init_struct.periph_addr = periph_addr;
  77. //外设地址不递增
  78. dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
  79. //外设地址的数据宽度为8位
  80. dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
  81. //DMA传输优先级为最高
  82. dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
  83. /* 禁止DMA传输循环模式 */
  84. dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE;
  85. /* 初始化DMA传输 */
  86. dma_single_data_mode_init(BSP_DMA, BSP_DMA_CHANNEL_TX, &dma_init_struct);
  87. /* 配置DMA通道的外设连接 */
  88. dma_channel_subperipheral_select(BSP_DMA, BSP_DMA_CHANNEL_TX, TX_DMA_SUBPERIPHERAL_ENUM);
  89. return 0;
  90. }
  91. //USART接收的dma配置
  92. int32_t usart5_dma_rx_init(uint32_t periph_addr)
  93. {
  94. /* 使能DMA时钟 */
  95. rcu_periph_clock_enable(BSP_DMA_RCU);
  96. /* 复位DMA并禁用DMA传输 */
  97. dma_deinit(BSP_DMA, BSP_DMA_CHANNEL_RX);
  98. /* 配置DMA传输结构体 */
  99. dma_single_data_parameter_struct dma_parameter;
  100. // DMA传输方向:从外设到内存
  101. dma_parameter.direction = DMA_PERIPH_TO_MEMORY;
  102. // 外设地址,指向要接收数据的外设寄存器地址
  103. dma_parameter.periph_addr = periph_addr;
  104. // 外设地址不递增
  105. dma_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
  106. // 外设地址的数据宽度为8位
  107. dma_parameter.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
  108. // 传输数据的内存地址,指向接收数据的缓存区
  109. dma_parameter.memory0_addr = (uint32_t)g5_recv_data;
  110. // 内存地址递增
  111. dma_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
  112. // 传输数据的大小,单位为字节
  113. dma_parameter.number = sizeof(g5_recv_data);
  114. // DMA传输优先级为最高
  115. dma_parameter.priority = DMA_PRIORITY_ULTRA_HIGH;
  116. // 非循环传输模式
  117. dma_parameter.circular_mode = DMA_CIRCULAR_MODE_DISABLE;
  118. dma_single_data_mode_init(BSP_DMA, BSP_DMA_CHANNEL_RX, &dma_parameter);
  119. /* 配置DMA通道的外设连接 */
  120. dma_channel_subperipheral_select(BSP_DMA, BSP_DMA_CHANNEL_RX, RX_DMA_SUBPERIPHERAL_ENUM);
  121. /* 使能DMA传输 */
  122. dma_channel_enable(BSP_DMA, BSP_DMA_CHANNEL_RX);
  123. //9.配置中断优先级
  124. //nvic_irq_enable(DMA1_Channel2_IRQn, 2, 2);
  125. // //8.使能DMA通道中断
  126. // dma_interrupt_enable(BSP_DMA,BSP_DMA_CHANNEL_RX,DMA_CHXCTL_FTFIE);
  127. //
  128. dma_interrupt_flag_clear(BSP_DMA,BSP_DMA_CHANNEL_RX,DMA_INT_FLAG_FTF);
  129. return 0;
  130. }
  131. /**
  132. * @brief 调试信息发送接口
  133. * @param data:调试数据指针;\
  134. * len:调试数据的数据长度
  135. * @retval 0或其他错误代码
  136. **/
  137. int32_t uart5_dma_send(uint8_t *data,uint32_t len)
  138. {
  139. /* 关闭DMA通道 */
  140. dma_channel_disable(BSP_DMA, BSP_DMA_CHANNEL_TX);
  141. /* 清除DMA传输完成标志 */
  142. dma_flag_clear(BSP_DMA, BSP_DMA_CHANNEL_TX, DMA_FLAG_FTF);
  143. /* 配置DMA传输的内存地址和传输数据大小 */
  144. dma_memory_address_config(BSP_DMA, BSP_DMA_CHANNEL_TX, DMA_MEMORY_0, (uint32_t)data);
  145. dma_transfer_number_config(BSP_DMA, BSP_DMA_CHANNEL_TX, len);
  146. /* 使能DMA通道 */
  147. dma_channel_enable(BSP_DMA, BSP_DMA_CHANNEL_TX);
  148. return 0;
  149. }
  150. //解析速度数据
  151. void parse_speed(void){
  152. //解析的位数
  153. int i = 0;
  154. //帧头数据是否已经解析
  155. int head = -1;
  156. //任务类型
  157. int type = -1;
  158. //数据长度
  159. int length = -1;
  160. //已经读取的数据长度
  161. int read_length = 0;
  162. //校验位
  163. float check = -1;
  164. while(1){
  165. //走到下一位进行
  166. int8_t data = g5_recv_data[i];
  167. /*------------------ 读取帧头数据 ------------------*/
  168. if(head==-1&&data!=0x7b){
  169. break;
  170. }
  171. if (head==-1&&data == 0x7b) {
  172. printf("recv head\n");
  173. head = 1;
  174. i++;
  175. continue;
  176. }
  177. /*------------------ 读取类型type ------------------*/
  178. if (type == -1) {
  179. //标识
  180. type = data;
  181. printf("recv type type=%d\n", type);
  182. i++;
  183. continue;
  184. }
  185. /*------------------ 读取数据长度 ------------------*/
  186. if (length == -1) {
  187. length = data;
  188. printf("recv length length=%d\n", length);
  189. i++;
  190. continue;
  191. }
  192. /*------------------ 读取数据 ------------------*/
  193. printf("-------------------- length=%d\n", length);
  194. //读取数据
  195. if (read_length < length) {
  196. printf("recv mini data\n");
  197. memcpy(&speed[read_length],&g5_recv_data[i],4);
  198. read_length += 1;
  199. i+=4;
  200. continue;
  201. }
  202. /*------------------ 验证数据结果是否正确 ------------------*/
  203. //校验位
  204. float check = 0.0;
  205. memcpy(&check,&g5_recv_data[i],4);
  206. printf("check:%f\n",check);
  207. float total = 0;
  208. total += type;
  209. total += length;
  210. for (int i = 0; i < length; ++i) {
  211. total += speed[i];
  212. }
  213. printf("total:%f\n", total);
  214. if(check!=total){
  215. break;
  216. }
  217. i+=4;
  218. printf("i=%d\n",i);
  219. int8_t tail = 0;
  220. memcpy(&tail,&g5_recv_data[i],1);
  221. printf("tail:%d\n",tail);
  222. break;
  223. }
  224. }
  225. //USART接收完成中断处理函数
  226. void USART5_IRQHandler(void)
  227. {
  228. //printf("usart idle\n");
  229. uint32_t recv_len = 0;
  230. if (usart_interrupt_flag_get(USART_NUM, USART_INT_FLAG_IDLE) != RESET)
  231. {
  232. /* 清除串口空闲中断标志 */
  233. usart_interrupt_flag_clear(USART_NUM, USART_INT_FLAG_IDLE);
  234. //清空缓冲区
  235. usart_data_receive(USART_NUM);
  236. /* 关闭 DMA 接收通道 */
  237. dma_channel_disable(BSP_DMA, BSP_DMA_CHANNEL_RX);
  238. /* 获取接收到的数据长度 256 */
  239. recv_len = sizeof(g5_recv_data) - dma_transfer_number_get(BSP_DMA, BSP_DMA_CHANNEL_RX);
  240. printf("recv_len:%d\n",recv_len);
  241. if (recv_len != 0 && recv_len < sizeof(g5_recv_data))
  242. {
  243. /* 将接收到的数据用 DMA 传输发送出去 hello\0*/
  244. //g6_recv_data[recv_len] = '\0';
  245. //printf("%s\n",g5_recv_data);
  246. //解析速度数据
  247. parse_speed();
  248. //TODO 需要操作小车移动
  249. printf("x:%f,y:%f,z:%f\n",speed[0],speed[1],speed[2]);
  250. /* 配置 DMA 接收传输的内存地址和传输数据大小 */
  251. // dma_memory_address_config(BSP_DMA, BSP_DMA_CHANNEL_RX, DMA_MEMORY_0, (uint32_t)g6_recv_data);
  252. // dma_transfer_number_config(BSP_DMA, BSP_DMA_CHANNEL_RX, sizeof(g6_recv_data));
  253. //清除DMA传输完成标志位,以便下一次DMA传输能够正常进行
  254. dma_flag_clear(BSP_DMA, BSP_DMA_CHANNEL_RX, DMA_FLAG_FTF);
  255. /* 重新开启 DMA 接收通道 */
  256. dma_channel_enable(BSP_DMA, BSP_DMA_CHANNEL_RX);
  257. }else{
  258. memset(g5_recv_data, 0, sizeof(g5_recv_data));
  259. }
  260. }
  261. return;
  262. }
  263. //全部初始化
  264. void usart5_dma_config(uint32_t baudval){
  265. //gpio初始化
  266. usart5_gpio_config();
  267. //usart参数配置
  268. usart5_param_config(baudval);
  269. //USART通过DMA发送配置
  270. usart5_dma_tx_init((uint32_t)(&USART_DATA(USART_NUM)));
  271. //USART通过DMA接收配置
  272. usart5_dma_rx_init((uint32_t)(&USART_DATA(USART_NUM)));
  273. }