CPU与外围设备之间的信息交换或计算机与计算机之间的信息交换称为通信。基
本的通信方式有两种,即并行通信和串行通信。
文章目录
- 一、串行通信基础
- 1.1 串行通信的方式
- 1.2 串行通信的数据传输形式
- 1.3 波特率
- 二、STM32的USART的结构特征(了解)
- 三、工作方式(掌握)
- 四、应用案例
一、串行通信基础
串行通信是数据字节的各位一位一位地依次传送的通信方式。串行通信的速度慢,但占用的传输线条数少,适用于远距离的数据传输。
并行通信数据字节的各位同时传送的通信方式。并行通信的有点是数据传送速度快,缺点是占用的传输线条数多,适用于近距离通信。在通信距离比较远的情况下成本比较高。
简单来说,串行就是数据都是在一根线上传输的,需要一个一个的进行传输,就像过独木桥一样。而并行就是多条线,数据可以同时的在多条线上进行传输。比较好理解。
1.1 串行通信的方式
从硬件上看,串行通信方式有单工通信、半双工通信和全双工通信。
(1)单工通信。数据只允许向一个方向进行传送,即数据发送设备只能发送数据,而数据接收设备只能接收数据。此时在数据发送设备与数据接收设备之间只需要一条数据传输线。
(2)半双工通信。数据允许向两个方向进行传送,但是传送数据的过程与接收数据的过程不能同时进行。即进行通信的两个设备都具有传送与接收的能力,但是在同一时刻只能一个设备进行数据传送而另一个设备进行数据接收。
(3)全双工通信。数据允许向两个方向进行传送,并且传送数据的过程与接收数据的过程可以同时进行。即进行通信的两个设备都具备传送与接收数据的能力,而且在同一时刻两个设备均可以发送与接收数据。
1.2 串行通信的数据传输形式
在串行通信中,接收端接收到一连串的数据流后,应正确地识别各个数据起始和结束位置,即保证接收端与发送端数据的同步,否则就无法保证数据的正确接收。为此需要制定一些共同遵守的约定,其中最重要的是字长设置,USART字长设置如下:
字节可以通过编程USART_CR1寄存器中的M位,选择成8位或9位。在起始位期间,TX引脚处于低电平,在停止位期间处于高电平。空闲帧为全1的完整数据帧,后面跟着包含了数据的一下帧的开始位。断开帧为全0的完整数据帧。在断开帧结束时,发送器再插入1或2个停止位来应答起始位。发送和接收由一共用的波特率发生器驱动,发送器和接收器的使能位分别置1时,产生时钟。
1.3 波特率
波特率即数据的传送速率。在串行通信中,每秒钟传送的二进制数的位数称为波特率,单位时比特/秒,或波特。波特率的倒数就是每一位数的传送时间,称为位传送时间,单位为秒。USART根据波特率发生器提供宽范围的波特率进行选择。
二、STM32的USART的结构特征(了解)
STM32有3~5个的全双工异步串行通信USART接口,可实现设备之间的串行数据传输。
STM32的USART外部引脚包括接收数据输入(RX)、发送数据输出(TX)、清除发送(nCTS)、发送请求(xRTS)和发送器时钟输出(CK),通过这些引脚可以与其他外部设备通信。
内部包括发送数据寄存器(TDR)、接收数据寄存器(RDR)、移位寄存器、IrDA串行红外编解码模块、硬件数据流控制器、时钟控制、发送控制、唤醒单元、接收控制、中断控制和波特率控制等。下图为USART结构图,来自STM32F103数据手册,了解即刻。
任何USART双向通信至少需要2个脚:RX和TX。当发送器被激活,并且不发送数据时,TX引脚处于高电平。在IrDA模式下,TX作为IRDA_OUT,RX作为IRDA_IN。nCTS和nRTS作用于调制解调。CK为发送器时钟输出,此引脚用于同步传输的时钟,阴部模式不用。
三、工作方式(掌握)
- 数据发送
发送器根据M位的状态发送8位或9位的数据。当发送使能位(TE)被置位时,发送移位寄存器中的数据在TX引脚上输出,相应的时钟脉冲在CK因脚伤输出。在USART发送期间,字符发送在TX引脚上首先移出数据的最低有效位。 - 数据接收
在USART接收期间,数据的最低有效位首先从RX引脚进。当一个字符被接收时,RXNE位被置位。它表明移位寄存器的内容被转移到RDR,也就是说,数据已经被接收并且可以被读出。如果RXNEIE位被设置,则产生中断。在接收期间如果检测到帧错误、噪声或溢出错误,错误标志将被置起。 - 分数波特率的产生
接收器和发送器的波特率在USARTDIV的整数和小数寄存器中的值应设置成相同的。其公式如下:
波特率 = f c k / 16 × U S A R T D I V . 波特率 = fck/16×USARTDIV. 波特率=fck/16×USARTDIV.
fck 为外设的时钟;USARTDIV是一个无符号的定位数,这12位的值在USART_BRR寄存器中设置。
四、应用案例
- 案例介绍
使用usart1实现与PC端上位机之间的串口通信功能,在上位机中输出相关数据。 - Usart.c文件——串口初始化
void UsartDriver_Init(void)
{
GPIO_InitTypeDef GPIO_InitStureture;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
// PA9 TX
GPIO_InitStureture.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStureture.GPIO_Pin = USART_GPIO_TX_PIN;
GPIO_InitStureture.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(USART_GPIO_PORT,&GPIO_InitStureture);
// PA10 rx
GPIO_InitStureture.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStureture.GPIO_Pin = USART_GPIO_RX_PIN;
GPIO_Init(USART_GPIO_PORT,&GPIO_InitStureture);
USART_InitStructure.USART_BaudRate = 9600;
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(USART_PORT,&USART_InitStructure);
USART_Cmd(USART_PORT,ENABLE);
}
/*串口1连续发送函数*/
void BdUsart1Trans(float *p, int16_t len)
{
uint16_t i;
for(i = 0;i < len; i++)
{
USART_SendData(USART1 , p[i]);
while(USART_GetFlagStatus(USART1 , USART_FLAG_TC) == RESET) {}; // FLAG=0,未发完,等待
}
}
/*串口1连续接收函数*/
void BdUsart1Recv(char *p, int16_t len)
{
uint16_t i;
for(i = 0;i < len; i++)
{
if(USART_GetFlagStatus(USART1 , USART_FLAG_RXNE) == SET)
{
p[i] = USART_ReceiveData(USART1);
}; // FLAG=1, 收到数据
}
}
- 如果使用printf和scanf实现串口数据的收发,需要对其进行重映射。
//从串口打印printf函数 ,注意:需要在编译器中的编译选项中Micorlib上面打勾
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (uint16_t) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
{}
return ch;
}
//从串口1中使用scanff输入函数
int fgetc(FILE *f)
{
while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET){}
return (int)USART_ReceiveData(USART1);
}
- main.c 文件——主程序文件
void main()
{
UsartDriver_Init();
LedDriver_Init();
while(1)
{
printf("Welcome!!!!");
}
}