通讯一:串口通信

一、引脚连接

-RXD:数据输入引脚。数据接受。
-TXD:数据发送引脚。数据发送。
在这里插入图片描述
在这里插入图片描述
在原理图中的TX、RX为模块的输出端与接收端,标号表示连载一起,单片机原理图上的连接点也是表示模块的引脚。
可以根据引脚再查看数据手册进行再次确认。

物理层通信

TTL电平:传输电压低,常用于近距离传输连接
RS232电平:传输电压较大,转换为RS232可用于较远距离数据传输连接
物理层接口标准

串口转(安装相应的驱动)

串口转USB:ch340芯片——1:2.4V~5V    0:0V~0.4V
串口转RS232:max232芯片——
串口转RS485:max485芯片

二、串口通信协议

起始位:1位
数据位:8-9位(一般为8位)
奇偶校验位:1或1.5或2位(一般用1位,设置为0—即不设置奇偶校验)
停止位:1位

串口通信协议图
波特率设置:在数据传输和接收双方,需要预先统一波特率,以便正确的传输数据。

波特率 = 时钟频率 / (分频系数 × (1 + 分频器值))
	   =串口时钟 / BRR

波特率与时间的关系:假定设置UART波特率为9600 N 8 1 (代表无校验8位数据位1位停止位)
9600表示每秒9600位,每个字节是8位, 如果外加1个起始位和1个停止位,那就要10个位才能传送1个字节, 理论速度为:9600/10 = 960 字节每秒

三、串口通信过程

串口数据传输过程

四、常用相关寄存器(具体查看寄存器手册)

USART框图

在这里插入图片描述

常用寄存器

USART_DR数据寄存器(data register)——发送、接受缓冲区
USART_CR数据寄存器(control register)
USART_BRR波特率寄存器
USART_SR状态寄存器(state registe)

SR寄存器——标志位
TC位:发送完成,当该位被置1,表示DR寄存器数据已经发送完成
RXNE位:接受寄存器非空(判断是否有数据传输进来,需要接受)
IDLE位:判断总线是非为空闲(判断数据是否是传输完成)

五、中断标志位(位于UARTx->SR状态寄存器)

在这里插入图片描述
在这里插入图片描述

六、串口配置一般步骤(重要)

1.串口时钟使能,GPIO时钟使能:RCC_APB2PeriphClockCmd();
2.串口复位:USART_DeInit(); 这一步不是必须的
3.GPIO端口模式设置:GPIO_Init(); 模式设置为GPIO_Mode_AF_PP
4.串口参数初始化:USART_Init();
5.开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)
	  void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);//设置分组函数调用
      NVIC_Init();//抢占优先级,相应优先级,设置串口中断线
      USART_ITConfig();//中断触发源,(RXNE/IDLE)
6.使能串口:USART_Cmd();//使能发送控制器与接收控制器
7.编写中断处理函数:USARTx_IRQHandler();		//串口读取数据也相当于清除中断

8.串口数据收发:
void USART_SendData();//发送数据到串口,DR
uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据
9.串口传输状态获取:
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);

七、中断接收方法(最好会写)

方法1.字符\r\n

注释:程序要求,发送的字符是以回车换行结束(0x0D,0x0A
假如发送数据为:ABCDEFGHI…….\r\n
字符\r\n 对应ASCII表的十进制数据是
ABCDEFGHI…….(0x0D),(0x0A)

1.宏定义一个USART_REC_LEN用于表示数组长度 
#define USART_REC_LEN   200 						 	//定义最大接收字节数 200
2.设置一 个 数 组USART_RX_BUF[]
 u8  USART_RX_BUF[USART_REC_LEN];			              //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
3.设置一个接收状态全局变量 USART_RX_STA(记录数组的位置)
 u16 USART_RX_STA;         									//接收状态标记

在这里插入图片描述
方法1程序逻辑图
代码:(直接用)

void USART1_IRQHandler()
{
	u8 Res;

if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)判断是否为读中断
{
	Res =USART_ReceiveData(USART1);	//读取接收到的数据
	
	if((USART_RX_STA&0x8000)==0)//接收未完成
	{
		if(USART_RX_STA&0x4000)//接收到了0x0d
		{
			if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
			else USART_RX_STA|=0x8000;	//接收完成了 
		}
		else //还没收到0X0D
		{	
			if(Res==0x0d)USART_RX_STA|=0x4000;//第十四位写为一
			else
			{
				USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
				USART_RX_STA++;
				if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
			}		 
		}
	 }   		 
   } 
}

if((USART_RX_STA&0x8000)==0)
可用于判断是否有数据需要接收

方法2.中断标志位(RXNE.IDLE)

USART_IT_RXNE 接收缓存器标志位 如果有数据接收到该位置一
USART_IT_IDLE 空闲标志位 如果数据接收完毕该位置一

1.宏定义一个USART_REC_LEN用于表示数组长度 
#define USART_REC_LEN   200 						 	//定义最大接收字节数 200
2.设置一 个 数 组USART_RX_BUF[]
 u8  USART_RX_BUF[USART_REC_LEN];			              //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
 3.设置一个接收状态全局变量 USART_RX_STA(记录数组的位置)
 u16 USART_RX_STA;         									//接收状态标记
 
 USART_RX_STA = 1;//数据接收完毕
 USART_RX_STA = 0;//数据尚未接收完毕

代码:(直接用)

	void USART1_IRQHandler() 
	{	
		u8 res;
	
	if(USART_GetITStatus(USART1,USART_IT_RXNE))	//SR寄存器的  RXNE位,读寄存器非空,判断是否有数据
	{
		res = USART_ReceiveData(USART1);									//读取数据相当于清除中断
		USART_RX_BUF[USART_RX_STA&0X3FFF]=res;						//将接收到数据存入数组
		USART_RX_STA++;																		//数组长度变量++
		if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接受的数据长度超过数组最大值,重新开始
	}
	
	if(USART_GetITStatus(USART1,USART_IT_IDLE))	//SR寄存器的  IDLE位,判断总线是否空闲,也就是判断是否接受完数据
	{
		res = USART1->SR;
		res = USART1->DR;	//清空闲中断标志位,看中文数据操作手册:先读SR,再读DR,后清除中断
		USART_RX_STA|=0x8000;//第十五位置一
	}
}

注意事项:注意IDLE的使能添加:USART_ITConfig

if((USART_RX_STA&0x8000))
可用于判断是否有数据需要接收

注意调用清0

	USART_RX_STA=0;
	memset(USART_RX_BUF,0,200);

方法3.通过接收超时判断

假设传输速度位9600bit/s
现传输一个9600bit的数据需要1秒钟
通过判断USART_IT_RXNE 总线上在一个字节的时间内没有再接收到数据时发生。 (模仿空闲中断)

1.宏定义一个USART_REC_LEN用于表示数组长度 
#define USART_REC_LEN   200 						 	//定义最大接收字节数 200
2.设置一 个 数 组USART_RX_BUF[]
 u8  USART_RX_BUF[USART_REC_LEN];			              //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
 3.设置一个接收状态全局变量 USART_RX_STA(记录数组的位置)
 u16 USART_RX_STA;         									//接收状态标记

方法4.缓存队列

可以实现边接收数据,边发送数据

八、串口实现printf打印(写在串口模块)(直接用,最好会写)

//加入以下代码,支持printf函数,而不需要选择use MicroLIB,避免出现半主机模式  ,写在模块程序上面
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ int handle; 
}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ x = x; } 

//重定义fputc函数 
int fputc(int ch, FILE *f)		//文件流方式
{      
    while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   //寄存器TC位,在没有置1时一直循环,置1后跳出循环
    USART1->DR = (u8) ch;  
   return ch;
}
#endif 

九、发送函数封装(最好会写)

//发送一个字节数据
void usart_sendbyte(USART_TypeDef* pUSARTx, uint8_t data)
{
	//发送一个字节数据
	USART_SendData(pUSARTx,data);
	//等待发送数据寄存器为空
	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE) == RESET);
}
 
//发送一个数组数据
void usart_sendarr(USART_TypeDef* pUSARTx, uint8_t *arr, uint8_t len)
{
	uint8_t i;
	for(i = 0; i < len; i++)
	{
		//发送一个字节数据
		usart_sendbyte(pUSARTx,*arr++);
	}
	//等待发送完成
	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC) == RESET);
}
 
//发送字符串数据
void usart_sendstr(USART_TypeDef* pUSARTx, char *str)
{
	do
	{
		//发送一个字节数据
		usart_sendbyte(pUSARTx,*str++);
	}while((*str) != '\0');
	//等待发送完成
	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC) == RESET);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

好好睡觉好好吃饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值