1.UART串口通信
处理器与外部设备通信的两种方式
并行通信 -传输原理:数据各个位同时传输。
优点:速度快
缺点:占用引脚资源多
串行通信 -传输原理:数据按位顺序传输。
优点:占用引脚资源少
缺点:速度相对较慢
2.按照数据传送方向分为:
1.单工:数据传输只支持数据在一个方向上传输
2.半双工:允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;
3.全双工:允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。
3.串行通信的通信方式
同步通信:带时钟同步信号传输。 -SPI,IIC通信接口(I2C)
异步通信:不带时钟同步信号。 -UART(通用异步收发器),单总线
4.UART异步通信方式引脚连接方法:
-RXD:数据输入引脚。数据接受。
-TXD:数据发送引脚。数据发送。
STM32串口异步通信需要定义:
1. 起始位
2. 数据位(8位或者9位)
3.奇偶校验位(第9位)
4. 停止位(1,1.5,2位)
5.波特率设置
串口按位(bit)发送和接收字节的通信方式。
通信可以分为同步串口通信和异步串口通信。
波特率:是一个衡量符号传输速率的参数。在单片机使用中,常用的波特率有9600、115200等。
数据位:通信中实际数据位的参数。
停止位:单个包的最后位。典型的值为1,1.5和2位。
校验位:判断是否有噪声干扰了通信或者是否传输和接收数据是否不同步。
5.USART数据的发送/接收原理
串行发送:CPU内部还是并行数据(即:保存在发送数据寄存器),按照发送时钟逐字位的将发送数据存入到移位寄存器,然后再通过TxD发送引脚逐位发送出去。
串口接收:外部数据逐位从RxD引脚被接收,按照接收时钟,又逐字位的将接收到的数据存入到移位寄存器,然后再保存到接收数据寄存器中,并被CPU读取。
注意:串口如果使用printf函数,一定要记得重写fputc函数,以及勾选Use Micro LIB。如果不勾选微库,则要添加“半主机模式的相应代码”,可百度查找。
重写的代码:
int fputc (int ch,FILE *f)
{
while ( (USART1->SR & 0x40) == 0 );//判断上一次发送是否完成。
USART1->DR=(u8) ch;
return ch;
}
6.i2c协议-物理层 (通信方式 与今天的内容无关 !!)
I2C主要特点如下所示:
只需要两条总线;
没有严格的波特率要求,例如使用RS232,主设备生成总线时钟;
所有组件之间都存在简单的主/从关系,连接到总线的每个设备均可通过唯一地址进行软件寻址; I2C是真正的多主设备总线,可提供仲裁和冲突检测;
传输速度分为四种模式:
1、标准模式:Standard Mode=100 Kbps(传输速度慢了,用的少)
2、快速模式:Fast Mode=400 Kbps(使用最多)
3、高速模式:High speed mode=3.4 Mbps(大部分设备不支持这么高的频率)
4、超快速模式:Ultra fast mode=5 Mbps 最大主设备数:无限制; 最大从机数:理论上是127(7位数存储,2的7次方等于128)。 另外连接到相同总线的I2C数量受到总线的最大电容400pF限制(测试SCL总线的电容值)。实际上还没到128V,就到达到电容限制了。一般都不会使用这么多设备,设备多了,通讯速度跟不上。
i2c通信协议通信协议:用来实现数据传输。
i2c物理总线:SCL(时钟线) SDA(数据线)
i2c通信协议是 串行、同步、半双工 的通信方式。
i2c物理总线中,SCL时钟线只能由MCU来控制。SDA数据线可以收发数据。i2c通信必须是MCU和i2c从设备之间的双方通信。一条i2c总线上可以挂载多个i2c从设备。在进行通信时,必须是MCU和i2c从设备之间的通信,MCU一次只能和一个i2c从设备通信。一条i2c总线上如果挂载多个i2c从设备,i2c总线通过器件地址来区别不同的i2c从设备。器件地址:每一个i2c从设备挂载到i2c总线之后,必须得到的一个在该总线上的编号。器件地址一般是一个8位的数据。器件地址的组成:4(设备ID) + 3(可编程地址) + 1(读写控制位) 总结:i2c通信协议是同步通信,MCU通过器件地址查找要通信的i2c从设备。
i2c通信协议时序:空闲信号、 起始信号、 读数据、 写数据、 发送应答、 接收应答、 终止信号
空闲信号:SCL : 高 SDA : 高
起始信号:SCL :高 SDA :由高变低
读数据: SCL :高 SDA :获取SDA上的电平
写数据: SCL :低 SDA :改变SDA电平状态
终止信号:SCL :高 SDA :由低变高
7.初始化串口 :
状态寄存器
当要发送数据时,TDR寄存器将存放着的待发送的数据传输到移位寄存器,当TDR的数据全部移位到移位寄存器,TXEIE置1,表明数据传输到移位寄存器。
当传送数据完成时,TC位置1。
当要接收数据时,移位寄存器把数据传输到DR寄存器中,当传输完成后,RXNE位置1,表明数据已完全传输到DR寄存器中,已准备好随时被读取。
数据寄存器
串口通信中,STM32F4有一个专门的数据寄存器用于存放数据,该寄存器的[8:0]位(共9位)为有效数据位,用于存放数据值。
( 数据寄存器包含两个寄存器,一个用于发送 (TDR),一个用于接收 (RDR) )
而我们知道一个字节是一个8位长的数据单位,可用一个字节表示一个字符、数字或其他字符,或者系列二进制位。
串口通信中寄存器每一次通过USART_SendData或USART_ReceiveData函数可以发送或接收一个字节的数据。
波特率寄存器
8.代码:
以 STM32F407 的串口1为例,跟大家讲下如何配置一个串口,使其能进行数据收发。
(1)串口初始化
在这一步中,需要:
① 对该串口使用到的 IO 口进行初始化和使能相应的时钟树,并对端口进行复用映射;
② 中断配置 (主要是一个优先级);
③ 串口初始化配置(奇偶校验、收发配置等);
④ 串口使能;
usart.c
void usart1_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;//定义对象
USART_InitTypeDef USART_InitStruct;//定义对象
NVIC_InitTypeDef NVIC_InitStruct;//定义对象
//1.时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟
//2.引脚初始化
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;//设置引脚为复用模式
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;//引脚的配置
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; //上拉电阻
GPIO_InitStruct.GPIO_Speed = GPIO_Fast_Speed;//引脚速度
GPIO_Init(GPIOA,&GPIO_InitStruct);//初始化
//串口1对应引脚复用映射
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
//3.串口初始化
USART_InitStruct.USART_BaudRate = 115200;//串口波特率
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_InitStruct.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStruct.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStruct.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_Init(USART1,&USART_InitStruct);//初始化串口1
//4.中断优先级配置 nvic Ustart1
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; //子优先级
NVIC_Init(&NVIC_InitStruct); //根据指定的参数初始化VIC寄存器
//5.开启中断
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
//6.中断使能
USART_Cmd(USART1,ENABLE);
}
int fputc (int ch,FILE *f)//使用printf() 需要定义
{
while ( (USART1->SR & 0x40) == 0 );//判断上一次发送是否完成。
USART1->DR=(u8) ch;
return ch;
}
void USART1_IRQHandler(void)//中断函数
{
char temp;
if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
temp = USART_ReceiveData(USART1);//(USART3->DR); //读取接收到的数据
switch(temp)
{
case '1':allshine();break;
case '2':allclose();break;
case '3':openbeep();break;
case '4':closebeep();break;
}
}
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
main.c
#include "stm32f4xx .h"
#include "usart.h"
#include "stdio .h "
int main ()
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
usartl_init();
printf( "hello ! ");
return 0;
}
9.补充的知识
或者用这个: