接着《AGV项目底层总结一》这篇博客,就AGV项目底层的代码设计技巧来进行讲解。
串口数据接收处理
串口指令的接收所用中断的方式,同时在中断里进行数据帧的识别,接收完整一帧数据后标志位置1,在main函数中通过标志位的判断来进行接收到指令的相应处理。
//串口1中断服务程序
void USART1_IRQHandler(void)
{
u8 Res;
static u8 reci_step = 0; //数据接收状态机
static u8 length = 0,i = 0; //指令长度计数指针
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
{
Res = USART1->DR; //(USART1->DR); //读取接收到的数据
switch(reci_step)
{
case 0: //接收判断帧头0xcd
if(Res == 0xcd){
reci_step = 1;
USART1_RX_STA = 1; //开始接收数据帧状态
}
else reci_step = 0;
break;
case 1: //接收判断帧头0xaa
if(Res == 0xaa) reci_step = 2;
else reci_step = 0;
break;
case 2: //接收判断帧头0x55
if(Res == 0x55) reci_step = 3;
else reci_step = 0;
break;
case 3: //接收指令长度
length = Res;
i = 0;
USART1_RX_BUF[i++] = Res;
reci_step = 4;
break;
case 4: //接收完整数据
USART1_RX_BUF[i++] = Res;
if(i > length){
reci_step = 0;
USART1_RX_STA = 2; //数据帧接收完成状态
}
break;
default:
reci_step = 0;
break;
}
}
}
数据总汇—结构体
在嵌入式的项目中,往往离不开许多数据的采集,本项目中数据采集后需要将数据通过串口进行传递,问题在于我们采集出来的数据大都是以变量的形式单独存。那么再批量发送之前,我们首先要做的就是将采集到的所有数据进行总汇。在项目中我们定义了一个结构体用来存放采集的所有数据,然后将此结构体的数据转移至数组中以便统一发送。话不多说,直接上代码。
//.h文件
#define SENSOR_DLEN 23
typedef struct {
int status; //小车状态
float power; //电源电压
float theta; //方位角
int encoder_ppr; //旋转一圈脉冲数
int encoder_delta_r;//右轮编码器
int encoder_delta_l;
int encoder_delta_car;//两车轮中心位移
float omga_r; //右轮转速
float omga_l;
float distance1; //第一个超声波距离值
float distance2;
float distance3;
float distance4;
float IMU[9]; //9轴数据
unsigned int time_stamp;//时间戳
}UPLOAD_STATUS;
extern UPLOAD_STATUS SENSOR_DATA;
//.c文件
UPLOAD_STATUS SENSOR_DATA;
u8 SendBuff[119]; //发送缓存数组
void SEND_SENSOR_DATA(void)
{
//调用DMA控制发送数据
int i;
static int j = 0;
SendBuff[0] = 0xcd;
SendBuff[1] = 0xeb;
SendBuff[2] = 0xd7;
SendBuff[3] = sizeof(SENSOR_DATA)/4*5;
for(i = 0; i < SENSOR_DLEN; i++)
{
SendBuff[4+i*5] = *(((u8 *)(&SENSOR_DATA))+i*4+0);
SendBuff[5+i*5] = *(((u8 *)(&SENSOR_DATA))+i*4+1);
SendBuff[6+i*5] = *(((u8 *)(&SENSOR_DATA))+i*4+2);
SendBuff[7+i*5] = *(((u8 *)(&SENSOR_DATA))+i*4+3);
SendBuff[8+i*5] = 0x20;
}
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); //使能串口1的DMA发送
MYDMA_Enable(DMA1_Channel4,119);//搬运一次串口数据
SENSOR_DATA.time_stamp++;//每发送一次时间戳加1
}
多字节数据的串口发送
总所周知,串口一次发送最多1个字节(8bit),当遇到多字节的数据需要通过其发送时,应该先对数据进行字节提取,然后按字节将数据进行串口发送。那么如何进行字节提取呢?现在介绍两种多字节数据的字节提取方式,直接上代码。
uint32_t rd_state;
abh_receive[3] = *(((uint8_t *)(&rd_state))+3); //可适用于浮点型
abh_receive[4] = *(((uint8_t *)(&rd_state))+2);
abh_receive[5] = *(((uint8_t *)(&rd_state))+1);
abh_receive[6] = *(((uint8_t *)(&rd_state))+0);
abh_receive[7] = last_pulse1 >>24; //只适用于整形
abh_receive[8] = last_pulse1 >>16;
abh_receive[9] = last_pulse1 >>8 ;
abh_receive[10] = last_pulse1 ;