基于STM32F103ZET6串口实验

文章最后是串口中断的总结及算法
串口的重要性大家都知道!mcu外部的重要接口,也是软件调试的重要调试方式,不管是调试串口,还是通信串口,原理都是一样,这次我们将使用串口1来接收pc发出的数据,再将数据发回给pc,我们使用的是正点原子板载usb串口。
接下来我们要进行哪些大概步骤:
1)使用gpio,gpio初始化(时钟使能)
2)使用串口,串口初始化(时钟使能,复位)
3)使用中断,中断初始化(开启使能)
4)中断函数编写(包括数据接收)
5)主函数实现数据发送给pc
串口配置
先从简单的开始
定义串口的头文件usart.c
#ifndef USART_H
#define USART_H
#define len 64//接收数据的最大个数buff
#include “sys.h”//io口的操作头文件包含

extern u8 bufff[len];
extern u16 USART_RX_STA;//接收数据标志变量
extern void usart_init(u32 bound);//串口初始化
#endif
这个都没什么说的,重点是在源文件!

定义源文件usart.c
#include “sys.h”
#include “usart.h”
u8 bufff[len];
u16 USART_RX_STA=0;
void usart_init(u32 bound)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);

USART_InitStructure.USART_BaudRate=bound;
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
USART_InitStructure.USART_Parity=USART_Parity_No;
USART_InitStructure.USART_StopBits=USART_StopBits_1;
USART_InitStructure.USART_WordLength=USART_WordLength_8b;
USART_Init(USART1,&USART_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;
NVIC_Init(&NVIC_InitStructure);

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1, ENABLE);

}
void USART1_IRQHandler(void)
{
unsigned char res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
res=USART_ReceiveData(USART1);
if((USART_RX_STA&0x8000)0)
{
if((USART_RX_STA&0x4000))
{
if(res
0x0A)
{
USART_RX_STA|=0x8000;
}
else
{
USART_RX_STA=0;
}
}
else
{
if(res==0x0d)
{

				USART_RX_STA|=0x4000;
			}
			else 
			{
				bufff[USART_RX_STA&0x3FFF]=res;
					USART_RX_STA++;
					if(63<(USART_RX_STA&0x3FFF))
					{
						USART_RX_STA=0;
					}
			}
		}
	}
}

}
新手看到这里都要哭了,告诉你!别慌,其实就一个函数是关键!
uint16_t USART_ReceiveData(USART_TypeDef USARTx);
也就是res=USART_ReceiveData(USART1);
*
这是中断响应接收到的一个字节数据!
其他的程序全是对这个接收到的数据进行一个数据处理!这个可以根据自己的通信协议来更改
USART_RX_STA是一个16位的二进制数据,用来保存数据的指标
如:数据的帧头,帧尾等等

当然可以根据自己的喜好,变换处理的方式,上面只是一个例子,初始化函数不用看,解释一下中断函数这个例子:
思路:如果特定数据(数据开始或者结束接收)到来,在定义的USART_RX_STA中标记出数据(数据开始或者结束接收)到来,在下一次通信(真实需要传输的)数据到来时,查看USART_RX_STA中的标志位,判断数据是否接收完毕,如果没有,此数据保存,继续接受收据,直到收到帧尾,如果已经接收完毕,抛弃该数据!
USART_RX_STA:
在这里插入图片描述
定义主函数main.c

#include “led.h”
#include “delay.h”
#include “key.h”
#include “usart.h”
#include “sys.h”
#include “stdio.h”

int main(void)
{
u16 le;
u8 i;
delay_init();
LED_Init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
usart_init(115200);
while(1)
{
if((USART_RX_STA&0x8000))
{
USART_SendData(USART1, 0x00);
le=(USART_RX_STA&0x3FFF);
for(i=0;i<le;i++)
{
USART_SendData(USART1, bufff[i]);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==0)
{
;
}
}
USART_RX_STA=0;
}
else
{
LED0=0;
delay_ms(500);
}
}
}
USART_RX_STA中我们可以判断出数据是否接收完整,我们在main函数中用while循环一直检测该数据,一旦成功,将发出数据到pc,这里的led灯来指示系统正常工作中!
USART_GetFlagStatus(USART1,USART_FLAG_TC)是单个字节数据发送完成标志位
如果单个字节发送成功,将会被置1;跳出空循环继续进行bufff中的字节发送,发送完毕后,我们需要将USART_RX_STA的标志位清零,清零后我们的STM32才会继续进行数据的接收!
有点小伙伴就要想了,如果发送完才能接收,那要是数据过多怎么办,会不会造成数据的阻塞?所以这时候就可以更改自己的逻辑结构,算法,使得满足你自己所想的通信协议要求!
比如:我可以接收发送来的所有数据(用个定时器计时,两个中断相应的间隔时间超多多少ms停止本buff缓存数据),再用下一个buff接收下一组数据,不一定在线程中就一个数据缓存buff,就一个buff只能做一些简单的数据交互,这些的这些都等着自己去探索,希望我的讲解对你有所帮助!
其他
希望大家对于自己理解的串口多多交流,我们在生活中一般会使用一个线程在专门接收数据,这样比较耗资源,有没有更好的方法来接收数据,还请大家留言!谢谢

发布了5 篇原创文章 · 获赞 9 · 访问量 2514

猜你喜欢

转载自blog.csdn.net/weixin_42271802/article/details/104446834
今日推荐