目录:
学习内容:
USART串口的收发,以及串口的协议。
首先我们需要对pintf()函数进行重定位,让我们以后使用他时能够直接从串口打印信息,大大的方便了我们的程序调试。
#include "stdio.h" /* printf函数需要这个头文件 */
/* 下面这段就是对串口的重定位
* 作用就是将printf打印的信息输出到串口
*/
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
_sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
USART1->DR = (u8) ch;
return ch;
}
#endif
这里直接添加照搬 。回到正题,我们来配置串口。我们串口接受信息是需要进入中断来完成的,那么我们同时需要编写串口的中断函数,同时我们还需要配置中断函数优先级需要配置NVIC控制器。
1.初始化串口GPIO,
2.配置串口的参数并且初始化,波特率等等
3.配置NVIC使能USART1_IRQn,初始化NVIC
4.打开中断的接收模式 使能中断。
void USART_INIT(u32 borund)
{
GPIO_InitTypeDef GPIO_Str;/* GPIO结构体初始化GPIO */
NVIC_InitTypeDef NVIC_Str;/* NVIC控制器结构体 */
USART_InitTypeDef USART_Str;/* 串口结构体初始化串口 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);
//配置GPIO
GPIO_Str.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Str.GPIO_Pin=GPIO_Pin_9;
GPIO_Str.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_Str);
GPIO_Str.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Str.GPIO_Pin=GPIO_Pin_10;
GPIO_Init(GPIOA,&GPIO_Str);//配置脚管
//配置串口 波特率115200,无奇偶校验,一位停止位,帧长度8
USART_Str.USART_BaudRate=borund;
USART_Str.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_Str.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
USART_Str.USART_Parity=USART_Parity_No;
USART_Str.USART_StopBits=USART_StopBits_1;
USART_Str.USART_WordLength=USART_WordLength_8b;
USART_Init(USART1,&USART_Str);//初始化usart1
//配置中断优先级
NVIC_Str.NVIC_IRQChannel=USART1_IRQn;
NVIC_Str.NVIC_IRQChannelPreemptionPriority=0;
NVIC_Str.NVIC_IRQChannelSubPriority=0;
NVIC_Str.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_Str); //中断分租管理初始化
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//接收终中断模式
USART_Cmd(USART1,ENABLE);
}
完成这些我们串口的配置完成了,现在就差中断服务函数的了。我们来编写中断服务函数,注意中断服务函数的名字是固定的,在底层汇编上就叫这个 ,名字不要敲错。附上一张汇编层面中断向量表。
void USART1_IRQHandler(void) //串口协议 p结束标志
{
u8 Res;
/* 判断是否接受到信息 */
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
/* 接受到就放进Res */
Res=USART_ReceiveData(USART1);
/* 判断Res是不是 ‘p’ */
if(Res != 'p') //p作为结束标记
{
/* 不是‘p’存进USART_RX_BUF */
USART_RX_BUF[k] = Res;
k++;
}
/* 是‘p’意味着接受完成 */
else if(Res == 'p')
{
USART_RX_BUF[k]='\0';
b=1; //接收完成标志位
}
}
}
中断里的接受协议很简单 就是xxxp就行,当然光是一个p只是代表我们接受完成,上位机会传很多坐标,为了防止确实接收到了p但是前面的某些字符没有正确接收,我对每个坐标之间放了个 其他字符进行判断。
例如 d8000s8000e8000p,(不知道为什么现在想想好像没必要)
解析的话直接判断USART_RX_BUF[0] [5] [10],是否分别等于d,s,e。如果是那么接受完全,不是的花就清空。上图:
void data_format(int * road_data_turn,int *road_data_arge,int *led_data)
{
int road_number_q,road_number_b,road_number_s,road_number_g,road_number;
int road_sum_q,road_sum_b,road_sum_s,road_sum_g,road_deep_sum;
int led_sum_q,led_sum_b,led_sum_s,led_sum_g,led_sum;
if(USART_RX_BUF[0] == 'd' && USART_RX_BUF[5] == 's' && USART_RX_BUF[10] == 'e')
{
//printf("ok!!!!!");
road_number_q = (USART_RX_BUF[1] - '0')*1000;
road_number_b = (USART_RX_BUF[2] - '0')*100;
road_number_s = (USART_RX_BUF[3] - '0')*10;
road_number_g = (USART_RX_BUF[4] - '0')*1;
road_number = road_number_q+road_number_b+road_number_s+road_number_g;
*road_data_turn = road_number;
//printf("road_number = %d ",road_number);
road_sum_q = (USART_RX_BUF[6] - '0')*1000;
road_sum_b = (USART_RX_BUF[7] - '0')*100;
road_sum_s = (USART_RX_BUF[8] - '0')*10;
road_sum_g = (USART_RX_BUF[9] - '0')*1;
road_deep_sum = road_sum_q+road_sum_b+road_sum_s+road_sum_g;
*road_data_arge = road_deep_sum;
//printf("road_deep_sum = %d ",road_deep_sum);
led_sum_q = (USART_RX_BUF[11] - '0')*1000;
led_sum_b = (USART_RX_BUF[12] - '0')*100;
led_sum_s = (USART_RX_BUF[13] - '0')*10;
led_sum_g = (USART_RX_BUF[14] - '0')*1;
led_sum = led_sum_q+led_sum_b+led_sum_s+led_sum_g;
*led_data = led_sum;
//printf("led_sum = %d\r\n",led_sum);
}
}
这里笔者犯傻了当时没想 这么多直接硬刚,其实有很多办法去很简洁的处理字符串数字转十进制。大伙看看就行别和我一样傻。
那么到这里串口和简单的协议也就结束了,我也看了原子的教程上的协议emmm很复杂,就想着自己先弄个简单的能顺利的完成他该完成的任务就行。
下一章节会优先更新个上位机的串口,基于Pyserial,然后再讲讲I2c和6050,有问题的地方请留言。