通信,最少要有两个对象,一个收,一个发。根据数据通信是否同步,可分为同步通信和异步通信。
同步通信:
一般情况下同步通信指的是通信双方根据同步信号进行通信的方式。
比如通信双方有一个共同的时钟信号,通讯中通常双方会统一规定在时钟信号的上升沿或下降沿对数据线进行采样。

异步通信:
是指数据传输速度匹配依赖于通信双方有自己独立的系统时钟,大家约定好通信的速度。
异步通信不需要同步信号,但是并不是说通信的过程不同步。

串行通信:指的是同一时刻只能收或发一个bit位信息。因此只用1根信号线即可。
-串行传输:数据按位顺序传输。
-优点:占用引脚资源少
-缺点:速度相对较慢
并行通信:指的是同一时刻可以收或发多个bit位的信息,因此需要多根信号线才行
-并行传输:数据各个位同时传输。
-优点:速度快
-缺点:占用引脚资源多
单工:要么收,要么发,只能做接收设备或者发送设备。比如收音机
半双工:可以收,可以发,但是不能同时收发, 比如对讲机
全双工:可以在同一时刻既接收,又发送。 比如手机

USART: Universal Synchronous Asynchronous Receiver and Transmitter的缩写,
即通用同步异步收发器可以灵活地与外部设备进行全双工数据交换。
UART 外设(Universal Asynchronous Receiver and Transmitter),
它是在 USART基础上裁剪掉了同步通信功能,只有异步通信。简单区分同
步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是 UART。
USART 在 STM32应用最多莫过于“打印”程序信息,一般在硬件设计时都会预留一个 USART通信接口连接电脑,用于在调试程序是可以把一些调试信息“打印”在电脑端的串口调试助手工具上,从而了解程序运行是否正确、指出运行出错位置等等。

STM32F407有四个 USART 和两个 UART,其中 USART1和 USART6 的时钟来源于 APB2 总线时钟,其最大频率为 84MHz,其他四个的时钟来源于 APB1总线时钟,其最大频率为 42MHz。
中文参考手册2.1章、数据手册2.2 table4


串口通信接口种类很多,下面几种都是串口


一般不设置默认是下面这种数据类型,可以配置8-9位的数据位,可选奇偶校验位和1个停止位。



中文参考手册26
位 7 TXEIE:TXE 中断使能 (TXE interrupt enable)
此位由软件置 1 和清零。
0:禁止中断
1:当 USART_SR 寄存器中 TXE=1 时,生成 USART 中断。
位 6 TCIE:传送完成中断使能 (Transmission complete interrupt enable)
此位由软件置 1 和清零。
0:禁止中断
1:当 USART_SR 寄存器中 TC=1 时,生成 USART 中断
位 5 RXNEIE:RXNE 中断使能 (RXNE interrupt enable)
此位由软件置 1 和清零。
0:禁止中断
1:当 USART_SR 寄存器中 ORE=1 或 RXNE=1 时,生成 USART 中断
位 3 TE:发送器使能 (Transmitter enable)
该位使能发送器。该位由软件置 1 和清零。
0:禁止发送器
1:使能发送器
注意:1:除了在智能卡模式下以外,传送期间 TE 位上的“0”脉冲(“0”后紧跟的是“1”)
会在当前字的后面发送一个报头(空闲线路)。
2:当 TE 置 1 时,在发送开始前存在 1 位的时间延迟。
位 2 RE:接收器使能 (Receiver enable)
该位使能接收器。该位由软件置 1 和清零。
0:禁止接收器
1:使能接收器并开始搜索起始位
控制寄存器 2 (USART_CR2) 略
位 31:16 保留,必须保持复位值
位 15:4 DIV_Mantissa[11:0]:USARTDIV 的尾数 这 12 个位用于定义 USART 除数 (USARTDIV) 的尾数
位 3:0 DIV_Fraction[3:0]:USARTDIV 的小数 这 4 个位用于定义 USART 除数 (USARTDIV) 的小数。当 OVER8 = 1 时,不考虑 DIV_Fraction3 位,且必须将该位保持清零。

位 7 TXE:发送数据寄存器为空 (Transmit data register empty)
当 TDR 寄存器的内容已传输到移位寄存器时,该位由硬件置 1。如果 USART_CR1 寄存器
中 TXEIE 位 = 1,则会生成中断。通过对 USART_DR 寄存器执行写入操作将该位清零。
0:数据未传输到移位寄存器
1:数据传输到移位寄存器
注意:单缓冲区发送期间使用该位。
位 6 TC:发送完成 (Transmission complete)
如果已完成对包含数据的帧的发送并且 TXE 置 1,则该位由硬件置 1。如果 USART_CR1 寄存
器中 TCIE = 1,则会生成中断。该位由软件序列清零(读取 USART_SR 寄存器,然后写入
USART_DR 寄存器)。TC 位也可以通过向该位写入‘0’来清零。建议仅在多缓冲区通信
时使用此清零序列。
0:传送未完成
1:传送已完成
位 5 RXNE:读取数据寄存器不为空 (Read data register not empty)
当 RDR 移位寄存器的内容已传输到 USART_DR 寄存器时,该位由硬件置 1。如果
USART_CR1 寄存器中 RXNEIE = 1,则会生成中断。通过对 USART_DR 寄存器执行读入
操作将该位清零。RXNE 标志也可以通过向该位写入零来清零。建议仅在多缓冲区通信时使
用此清零序列。
0:未接收到数据
1:已准备好读取接收到的数据
Data register
偏移地址:0x04
复位值:0xXXXX XXXX
位 31:9 保留,必须保持复位值
位 8:0 DR[8:0]:数据值
包含接收到数据字符或已发送的数据字符,具体取决于所执行的操作是“读取”操作还是
“写入”操作。
因为数据寄存器包含两个寄存器,一个用于发送 (TDR),一个用于接收 (RDR),因此它具有
双重功能(读和写)。
TDR 寄存器在内部总线和输出移位寄存器之间提供了并行接口(参见图 1)。
RDR 寄存器在输入移位寄存器和内部总线之间提供了并行接口。
在使能奇偶校验位的情况下(USART_CR1 寄存器中的 PCE 位被置 1)进行发送时,由于
MSB 的写入值(位 7 或位 8,具体取决于数据长度)会被奇偶校验位所取代,因此该值不
起任何作用。
在使能奇偶校验位的情况下进行接收时,从 MSB 位中读取的值为接收到的奇偶校验位。


这里还是开启串口异步通信,让cubmx帮我们初始化默认参数。
- void USART1_PutChar(uint8_t ch)
- {
- while(!(USART1->SR & (1<<7))); //1代表移位寄存器里数据已经发送完成,新数据可以发送了
- USART1->DR = ch; //把需要发送的数据传到数据寄存器
- }
-
- uint8_t USART1_GetChar(void)
- {
- while(!(USART1->SR & (1<<5))); //移位寄存器已准备好读取接收的数据
- return USART1->DR; //读取DR数据寄存器
- }
-
-
-
- int main(void)
- {
- /* USER CODE BEGIN 1 */
-
- /* USER CODE END 1 */
-
- /* MCU Configuration----------------------------------------------------------*/
-
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
- HAL_Init();
-
- /* USER CODE BEGIN Init */
-
- /* USER CODE END Init */
-
- /* Configure the system clock */
- SystemClock_Config();
-
- /* USER CODE BEGIN SysInit */
-
- /* USER CODE END SysInit */
-
- /* Initialize all configured peripherals */
- MX_GPIO_Init();
- MX_USART1_UART_Init();
- /* USER CODE BEGIN 2 */
- uint8_t ch;
- /* USER CODE END 2 */
-
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- ch = USART1_GetChar(); //等待串口的数据接收
- USART1_PutChar(ch); //收到数据发送到串口
- /* USER CODE END WHILE */
-
- /* USER CODE BEGIN 3 */
-
- }
- /* USER CODE END 3 */
-
- }

(1)实验1:利用串口的收发函数(HAL_UART_Transmit)和(HAL_UART_Receive)代替寄存器写法
- int main(void)
- {
- /* USER CODE BEGIN 1 */
-
- /* USER CODE END 1 */
-
- /* MCU Configuration----------------------------------------------------------*/
-
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
- HAL_Init();
-
- /* USER CODE BEGIN Init */
-
- /* USER CODE END Init */
-
- /* Configure the system clock */
- SystemClock_Config();
-
- /* USER CODE BEGIN SysInit */
-
- /* USER CODE END SysInit */
-
- /* Initialize all configured peripherals */
- MX_GPIO_Init();
- MX_USART1_UART_Init();
- /* USER CODE BEGIN 2 */
- uint8_t buf[10];
- //HAL_UART_Transmit(&huart1,(uint8_t *)"UART SEND\r\n",10,1000);
- //printf("this is fpuc\r\n");
- /* USER CODE END 2 */
-
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- HAL_UART_Receive(&huart1,buf,5,1000);
- HAL_UART_Transmit(&huart1,buf,5,1000);
-
-
- /* USER CODE END WHILE */
-
- /* USER CODE BEGIN 3 */
-
- }
- /* USER CODE END 3 */
-
- }
思路:printf重定向,printf函数调用的是c库中的fputc函数(放在main函数之前)。因此我们如果重新写了fputc函数,就可以改变printf函数的功能,可以向串口打印输出。
- int fputc(int ch,FILE *f)
- {
- while(!(USART1->SR & (1<<7)));
- USART1->DR = (uint8_t) ch;
- return ch;
- }

总结上面讲述得都是应用层的开发,最常用得就是printf重定向了,方便我们打印调试。对于底层的UART协议栈,帧结构这里不详细讲了,先参考链接UART协议栈分析