小车通过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)));
}