小车通过PG8和PG14和鲁班猫通信,对应的就是USART5串口
USART5串口实现
usart5_rt.h
#ifndef UART5_RT_H#define UART5_RT_H#include "gd32f4xx.h"#include "systick.h"#include "stdio.h"#include "string.h"extern float speed[3];//RX和TX引脚时钟#define USART_TX_RX_RCU RCU_GPIOG//USART0时钟#define USART_RCU RCU_USART5//引脚类型#define USART_GPIO GPIOG//引脚编号#define USART_RX_PIN GPIO_PIN_9#define USART_TX_PIN GPIO_PIN_14//复用编号#define RX_ALT_NUM GPIO_AF_8#define TX_ALT_NUM GPIO_AF_8//USART编号#define USART_NUM USART5//USART中断配置#define NVIC_IRQ USART5_IRQn//USART0的DMA时钟#define BSP_DMA_RCU RCU_DMA1#define BSP_DMA DMA1#define BSP_DMA_CHANNEL_RX DMA_CH1#define BSP_DMA_CHANNEL_TX DMA_CH6//DMA外部连接#define RX_DMA_SUBPERIPHERAL_ENUM DMA_SUBPERI5#define TX_DMA_SUBPERIPHERAL_ENUM DMA_SUBPERI5//USART关于GPIO配置void usart5_gpio_config(void);//USART关于参数配置void usart5_param_config(uint32_t baudval);//DMA发送配置int32_t usart5_dma_tx_init(uint32_t periph_addr);//USART接收的dma配置int32_t usart5_dma_rx_init(uint32_t periph_addr);//包含gpio和usart参数配置void usart5_dma_config(uint32_t baudval);//通过DMA发送int32_t uart5_dma_send(uint8_t *data,uint32_t len);//解析速度void parse_speed(void);#endif
usart5_rt.c
#include "uart5_rt.h"//uint8_t g_send_data[256];//发送数据uint8_t temp5[1] = {0};//接收数据最终存放位置uint8_t g5_recv_data[256];//接收数据//x y及z的线速度float speed[3] = {0.0};void usart5_gpio_config(void){// ● 开启时钟(包括串口时钟和GPIO时钟)rcu_periph_clock_enable(USART_TX_RX_RCU);rcu_periph_clock_enable(USART_RCU);// ● 配置GPIO复用模式gpio_af_set(USART_GPIO,RX_ALT_NUM,USART_RX_PIN);gpio_af_set(USART_GPIO,TX_ALT_NUM,USART_TX_PIN);// ● 配置GPIO的模式gpio_mode_set(USART_GPIO,GPIO_MODE_AF,GPIO_PUPD_PULLUP,USART_RX_PIN);gpio_mode_set(USART_GPIO,GPIO_MODE_AF,GPIO_PUPD_PULLUP,USART_TX_PIN);// ● 配置GPIO的输出/* 配置TX为推挽输出 50MHZ */gpio_output_options_set(USART_GPIO, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, USART_RX_PIN);/* 配置RX为推挽输出 50MHZ */gpio_output_options_set(USART_GPIO, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, USART_TX_PIN);}void usart5_param_config(uint32_t baudval){//USART复位usart_deinit(USART_NUM);//波特率usart_baudrate_set(USART_NUM,baudval);//校验位usart_parity_config(USART_NUM,USART_PM_NONE);//一个周期发送的数据位数usart_word_length_set(USART_NUM,USART_WL_8BIT);//停止位usart_stop_bit_set(USART_NUM,USART_STB_1BIT);//先发送高位还是低位usart_data_first_config(USART_NUM,USART_MSBF_LSB);//串口使能usart_enable(USART_NUM);//发送功能配置usart_transmit_config(USART_NUM,USART_TRANSMIT_ENABLE);//接收配置usart_receive_config(USART_NUM,USART_RECEIVE_ENABLE);//接收中断配置nvic_irq_enable(NVIC_IRQ, 2, 2);//配置处理哪些中断//USART_INT_RBNE:接收到一个字符就会触发,需要保存接收的字符usart_interrupt_enable(USART_NUM, USART_INT_RBNE); // 读数据缓冲区非空中断和过载错误中断//USART_INT_IDLE:一帧数据接收完成 hello 可以打印对应的字符串usart_interrupt_enable(USART_NUM, USART_INT_IDLE); // DLE线检测中断/* 使能串口DMA发送 */usart_dma_transmit_config(USART_NUM, USART_TRANSMIT_DMA_ENABLE);/* 使能串口DMA接收 */usart_dma_receive_config(USART_NUM, USART_RECEIVE_DMA_ENABLE);//接收中断配置nvic_irq_enable(NVIC_IRQ, 2, 2);//USART_INT_IDLE:一帧数据接收完成 hello 可以打印对应的字符串usart_interrupt_enable(USART_NUM, USART_INT_IDLE); // DLE线检测中断}int32_t usart5_dma_tx_init(uint32_t periph_addr){/* 使能DMA时钟 */rcu_periph_clock_enable(BSP_DMA_RCU);/* 复位DMA并禁用DMA传输 */dma_deinit(BSP_DMA, BSP_DMA_CHANNEL_TX);/* 配置DMA传输结构体 */dma_single_data_parameter_struct dma_init_struct;//DMA传输方向:从内存到外设dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;//传输数据的内存地址// dma_init_struct.memory0_addr = (uint32_t)g_send_data;//内存地址递增dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;//传输数据的大小// dma_init_struct.number = sizeof(g_send_data);//外设地址dma_init_struct.periph_addr = periph_addr;//外设地址不递增dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;//外设地址的数据宽度为8位dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;//DMA传输优先级为最高dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;/* 禁止DMA传输循环模式 */dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE;/* 初始化DMA传输 */dma_single_data_mode_init(BSP_DMA, BSP_DMA_CHANNEL_TX, &dma_init_struct);/* 配置DMA通道的外设连接 */dma_channel_subperipheral_select(BSP_DMA, BSP_DMA_CHANNEL_TX, TX_DMA_SUBPERIPHERAL_ENUM);return 0;}//USART接收的dma配置int32_t usart5_dma_rx_init(uint32_t periph_addr){/* 使能DMA时钟 */rcu_periph_clock_enable(BSP_DMA_RCU);/* 复位DMA并禁用DMA传输 */dma_deinit(BSP_DMA, BSP_DMA_CHANNEL_RX);/* 配置DMA传输结构体 */dma_single_data_parameter_struct dma_parameter;// DMA传输方向:从外设到内存dma_parameter.direction = DMA_PERIPH_TO_MEMORY;// 外设地址,指向要接收数据的外设寄存器地址dma_parameter.periph_addr = periph_addr;// 外设地址不递增dma_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;// 外设地址的数据宽度为8位dma_parameter.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;// 传输数据的内存地址,指向接收数据的缓存区dma_parameter.memory0_addr = (uint32_t)g5_recv_data;// 内存地址递增dma_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;// 传输数据的大小,单位为字节dma_parameter.number = sizeof(g5_recv_data);// DMA传输优先级为最高dma_parameter.priority = DMA_PRIORITY_ULTRA_HIGH;// 非循环传输模式dma_parameter.circular_mode = DMA_CIRCULAR_MODE_DISABLE;dma_single_data_mode_init(BSP_DMA, BSP_DMA_CHANNEL_RX, &dma_parameter);/* 配置DMA通道的外设连接 */dma_channel_subperipheral_select(BSP_DMA, BSP_DMA_CHANNEL_RX, RX_DMA_SUBPERIPHERAL_ENUM);/* 使能DMA传输 */dma_channel_enable(BSP_DMA, BSP_DMA_CHANNEL_RX);//9.配置中断优先级//nvic_irq_enable(DMA1_Channel2_IRQn, 2, 2);// //8.使能DMA通道中断// dma_interrupt_enable(BSP_DMA,BSP_DMA_CHANNEL_RX,DMA_CHXCTL_FTFIE);//dma_interrupt_flag_clear(BSP_DMA,BSP_DMA_CHANNEL_RX,DMA_INT_FLAG_FTF);return 0;}/*** @brief 调试信息发送接口* @param data:调试数据指针;\* len:调试数据的数据长度* @retval 0或其他错误代码**/int32_t uart5_dma_send(uint8_t *data,uint32_t len){/* 关闭DMA通道 */dma_channel_disable(BSP_DMA, BSP_DMA_CHANNEL_TX);/* 清除DMA传输完成标志 */dma_flag_clear(BSP_DMA, BSP_DMA_CHANNEL_TX, DMA_FLAG_FTF);/* 配置DMA传输的内存地址和传输数据大小 */dma_memory_address_config(BSP_DMA, BSP_DMA_CHANNEL_TX, DMA_MEMORY_0, (uint32_t)data);dma_transfer_number_config(BSP_DMA, BSP_DMA_CHANNEL_TX, len);/* 使能DMA通道 */dma_channel_enable(BSP_DMA, BSP_DMA_CHANNEL_TX);return 0;}//解析速度数据void parse_speed(void){//解析的位数int i = 0;//帧头数据是否已经解析int head = -1;//任务类型int type = -1;//数据长度int length = -1;//已经读取的数据长度int read_length = 0;//校验位float check = -1;while(1){//走到下一位进行int8_t data = g5_recv_data[i];/*------------------ 读取帧头数据 ------------------*/if(head==-1&&data!=0x7b){break;}if (head==-1&&data == 0x7b) {printf("recv head\n");head = 1;i++;continue;}/*------------------ 读取类型type ------------------*/if (type == -1) {//标识type = data;printf("recv type type=%d\n", type);i++;continue;}/*------------------ 读取数据长度 ------------------*/if (length == -1) {length = data;printf("recv length length=%d\n", length);i++;continue;}/*------------------ 读取数据 ------------------*/printf("-------------------- length=%d\n", length);//读取数据if (read_length < length) {printf("recv mini data\n");memcpy(&speed[read_length],&g5_recv_data[i],4);read_length += 1;i+=4;continue;}/*------------------ 验证数据结果是否正确 ------------------*///校验位float check = 0.0;memcpy(&check,&g5_recv_data[i],4);printf("check:%f\n",check);float total = 0;total += type;total += length;for (int i = 0; i < length; ++i) {total += speed[i];}printf("total:%f\n", total);if(check!=total){break;}i+=4;printf("i=%d\n",i);int8_t tail = 0;memcpy(&tail,&g5_recv_data[i],1);printf("tail:%d\n",tail);break;}}//USART接收完成中断处理函数void USART5_IRQHandler(void){//printf("usart idle\n");uint32_t recv_len = 0;if (usart_interrupt_flag_get(USART_NUM, USART_INT_FLAG_IDLE) != RESET){/* 清除串口空闲中断标志 */usart_interrupt_flag_clear(USART_NUM, USART_INT_FLAG_IDLE);//清空缓冲区usart_data_receive(USART_NUM);/* 关闭 DMA 接收通道 */dma_channel_disable(BSP_DMA, BSP_DMA_CHANNEL_RX);/* 获取接收到的数据长度 256 */recv_len = sizeof(g5_recv_data) - dma_transfer_number_get(BSP_DMA, BSP_DMA_CHANNEL_RX);printf("recv_len:%d\n",recv_len);if (recv_len != 0 && recv_len < sizeof(g5_recv_data)){/* 将接收到的数据用 DMA 传输发送出去 hello\0*///g6_recv_data[recv_len] = '\0';//printf("%s\n",g5_recv_data);//解析速度数据parse_speed();//TODO 需要操作小车移动printf("x:%f,y:%f,z:%f\n",speed[0],speed[1],speed[2]);/* 配置 DMA 接收传输的内存地址和传输数据大小 */// dma_memory_address_config(BSP_DMA, BSP_DMA_CHANNEL_RX, DMA_MEMORY_0, (uint32_t)g6_recv_data);// dma_transfer_number_config(BSP_DMA, BSP_DMA_CHANNEL_RX, sizeof(g6_recv_data));//清除DMA传输完成标志位,以便下一次DMA传输能够正常进行dma_flag_clear(BSP_DMA, BSP_DMA_CHANNEL_RX, DMA_FLAG_FTF);/* 重新开启 DMA 接收通道 */dma_channel_enable(BSP_DMA, BSP_DMA_CHANNEL_RX);}else{memset(g5_recv_data, 0, sizeof(g5_recv_data));}}return;}//全部初始化void usart5_dma_config(uint32_t baudval){//gpio初始化usart5_gpio_config();//usart参数配置usart5_param_config(baudval);//USART通过DMA发送配置usart5_dma_tx_init((uint32_t)(&USART_DATA(USART_NUM)));//USART通过DMA接收配置usart5_dma_rx_init((uint32_t)(&USART_DATA(USART_NUM)));}
