写在最前
本文为个人学习Stm32所做笔记,实验环境为正点原子Stm32zet6精英板。在学习时在想,既然正点原子使用中断来实现实验功能,那么怎么不用中断来实现同样的功能,想想应该不难,本文代码均采用固件库编写,并且没有使用中断来实现功能,详细解析在最后。
一、串行通信与并行通信的概念
-
串行通信
概念:通信时,通信双方仅仅只有一根数据线,在数据线上,每个时刻仅能传送一位数据,也就是说数据在数据线上一位一位的传送。
优点:因为通信双方仅占用一根数据线,因此节约端口引脚
缺点:传输速度慢
-
并行通信
概念:通信时,通信双方采用多根数据线进行通信,每个时刻可以传送多位数据。
优点:传输速度快
缺点:通信双方采用多根数据线进行数据传输,占用引脚资源多
-
串行通信又可分为单工、半双工、全双工通信
单工:数据传输仅仅只能朝一个方向进行
半双工:数据传输可以双向进行,但同一时刻仅仅只能接收数据或者发送数据,接收数据和发送数据不能同时进行
全双工:数据传输可以双向进行,并且接收数据和发送数据可以同时进行(两根数据线,一根只负责发,另一根只负责收)
二、同步通信和异步通信
串行通信的通信方式还包括同步通信和异步通信两种:
-
同步通信:通信双方带时钟同步信号传输,常见同步串行通信方式有SPI、I2C
-
异步通信:通信双方不带同步时钟信号,是单总线形式,通信双方约定相同波特率来保证数据传输和接收的有效性;常见的异步串行通信方式有Uart、Usart.
波特率:每秒钟传输多少个码元,一个码元可以是一个比特位,也可以是多个比特位
Uart:全双工通用异步收发器
Usart:全双工通用同步异步收发器
三、Stm32-Usart框图
数据接收和发送时分别涉及接收/发送数据寄存器、接收/发送移位寄存器,数据发送时,数据先写入发送数据寄存器,然后经发送移位寄存器传送至TX口;接收数据时,数据经RX口到接收移位寄存器,然后到接收数据寄存器,至此,数据可读。
当有数据可读时,也就是有数据发送来时,状态寄存器SR对应的位会置位,标识有数据可读,用户可以从接收数据寄存器中读数据。发数据同理。
注:摘自stm32中文参考手册
四、Usart串口通信实验
4.1 实验思路
正点原子Stm32zet6精英板中,PA9和PA10复用为Usart1,PA9为发送端,PA10为接收端,即
PA9 – USART1_TX
PA10 – USART1_RX
同时,PA9和PA10连接到RS232转换器转换为USB接口,通过CH340虚拟为串口,在PC上安装CH340即可使用该USB串口,实际上是使用的PA9和PA10,也就是USART1。
4.2 USART1初始化
串口初始化,由于将PA9和PA10复用为USART1,而PA9对应的是发送端,PA10对用的是接收端,因此需要配置PA9为复用推挽输出方式,PA10配置为浮空输入方式:
- 使能GPIOA和USART1的时钟
- 配置PA9为复用推挽输出模式,PA10为输入浮空模式
- 配置串口信息,波特率、数据位、停止位、奇偶校验位、硬件流控制、发送和接收使能
- 使能串口
/*用到的头文件*/
#include "stm32f10x_gpio.h" //GPIO相关宏定义,结构体声明
#include "stm32f10x_rcc.h" //时钟相关函数声明
#include "stm32f10x_usart.h" //串口相关宏定义、结构体声明和函数声明
/*
* USART1 --> PA9 -- TX, PA10 -- RX
*/
void usart_init()
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef Usart_InitStructure;
/*使能GPIOA和USART1的时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/*配置PA9为推挽复用输出*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//推挽复用输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*配置PA10为浮空输入*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*配置串口信息 -- 波特率,停止位,数据位等*/
Usart_InitStructure.USART_BaudRate = 115200;//波特率115200
Usart_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据位
Usart_InitStructure.USART_StopBits = USART_StopBits_1;//1位停止位
Usart_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验
Usart_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流控制
Usart_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//发送和接收使能
USART_Init(USART1, &Usart_InitStructure);
/*使能串口*/
USART_Cmd(USART1, ENABLE);
}
4.3 USART使用
实现功能:判断是否有数据发送过来,若有数据过来,便将接收到的数据回传回去
USART_GetFlagStatus()函数讲解:
通过查看函数源码以及Stm32中文参考手册,通过传入该函数的入口参数来判断CR寄存器对应的那些位置1,此处需要监测的是是否有数据可读,因此传入USART_FLAG_RXNE,此为宏定义,其值为0x00000020,通过阅读该函数源码发现,若是CR寄存器的第五位置1,该函数返回1,否则返回0,而CR寄存器的第5位 置1 表示有读数据寄存器有数据可读,置0 表示读数据寄存器无数据可读。
int main()
{
uint16_t recvData = 0;
usart_init();
while(1)
{
/*判断是否收到数据,即读数据寄存器是否非空*/
if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE))
{
recvData = USART_ReceiveData(USART1);
USART_SendData(USART1, recvData);
}
}
}