> 技术文档 > STM32-USART串口配置教程和printf函数实现(寄存器版)

STM32-USART串口配置教程和printf函数实现(寄存器版)

本章概述思维导图


通信介绍

通信介绍概况

通信,至少是需要两个对象,一个收一个发数据

根据数据通信的传输时序协调方式,可分为:同步通信和异步通信;

根据数据通信的传输线路可分为:串行通信和并行通信;

根据数据通信的传输方向性及双向交互能力可分为:单工通信和双工通信(半双工通信和全双工通信)

同步通信和异步通信定义

同步通信:发送方与接收方通过共享时钟线的时钟信号,确保数据按固定时间间隔传输,接收方能准确预测数据到达时间;

异步通信:发送方与接收方无共享时钟线,通过数据包或数据帧格式(如起始信号/停止位)协调传输数据;

同步和异步的区别:同步通讯需要有时钟信号控制,通过时钟线的高低电平控制数据的收发;异步通信没有时钟信号控制,通过数据帧格式控制数据的收发(大家约定好通信速度(波特率));

小心得:就是一个有时钟线提供时钟时序,一个没有时钟线;

串行通信和并行通信定义

串行通信:数据按位顺序传输,使用单条线路进行数据得传输。例如,发送字节 10110010 时,先传 1,再传 0,以此类推。

并行通信:数据的多个位(通常8位、16位等)同时通过多条线独立线路并行传输。如传输字节 10110010,会使用8根数据线,每根线同时传1位。

串行和并行的区别;

串行通信指同一时刻,只能收或发一个bit位信息,因此只用一根数据信号线即可;并行通信指同一时刻,可以收或发多个bit位信息,因此需要多根数据信号线才行;

单工和半双工、全双工定义

单工通信:数据仅能沿固定方向单向传输,发送端与接收端角色不可互换。

应用场景:广播系统(电台→听众、卫星数据下行)、传感器网络(如温湿度传感器→数据中心)等;

半双工通信:同一信道分时复用,双方交替发送和接收;

应用场景:对讲机、传统Wi-Fi;

全双工通信:双方可同时发送和接收数据;

应用场景:电话通话、以太网交换机等;

单工和半双工、全双工的区别:

单工通信:单工要么收要么发,只能做接收设备或者发送设备。接收器不能发送数据给  发送器。例如:收音机; 

半双工通信:双发都可以发送数据,双方不能同时发送数据或接收数据;只有一根发送/接收数据信号线。(特点:可以收可以发,但是不能同时收发)例如:对讲机; 

全双工通信:双方可以同时发送或者接收数据;有两根发送/接收数据信号线;(特点:可以同时即发送又接收数据)例如:手机

USART串口通信

串口(USART)通讯:异步通讯、全双工、串行通讯、总线协议;

USART通用同步异步收发器,是一种通用的串行、异步/同步通信总线。该总线有两条数据信号线,可以实现全双工的发送和接收;

波特率:用于描述USART串口通信时的通信速度,其单位(bps)即每秒钟传送的位(bit) 的数量

上位机:就是连接串口的电脑或者手机上的APP软件;是在自动化控制系统中,用于监控 和控制下位机(如单片机、PLC等)的计算机。它可以直接发送操作指令给下位机, 并接收下位机的反馈数据,通过用户操作交互界面向用户展示数据。

USART采用帧格式从低位开始发送数据——>高位

串口通信是不允许连续发送,避免累积误差。所以发送完一字节数据后就得停止重新发送;

USART1串口1电路原理图

1. 分析原理图,查看对应引脚

分析原理图这是串口USART1实现下载程序功能

我们不能随意配置USART1的引脚,要根据STM32F103X引脚定义手册来查看USART1配置的引脚;

TXD发送数据脚--->PA10(数据接收脚)

RXD接收数据脚--->PA9 (数据发送脚)

串口属于自行控制数据的收发,所以我们应设置GPIO引脚模式为复用模式;

发送对接收;PA10设置为复用输入模式,PA9设置为复用输出模式;

2. 配置串口1(USART1)模块初始化函数

配置USART1串口初始化函数步骤:

1. 开时钟

2. 对串口1模块开启复位时钟,在取消复位;

3. 配置GPIO模式

4. 通过在USART_CR1寄存器上置位UE位来激活USART

5. 编程USART_CR1的M位来定义字长。

6. 在USART_CR2中编程停止位的位数。

7. 利用USART_BRR寄存器选择要求的波特率。

8. 设置USART_CR1中的TE位,发送一个空闲帧作为第一次数据发送。

9. 设置USART_CR1的RE位。激活接收器,使它开始寻找起始位。

代码示例:

#include \"USART1.h\"/* USART1串口初始化函数 形参bps——>保持通信的波特率 PA10设置为输入模式,PA9设置为复用输出模式;*/void USART1_Init(u32 bps){// 1. 开时钟 RCC->APB2ENR|=1<APB2ENR|=1<APB2RSTR|=1<APB2RSTR&=~(1<CRH&=0xfffff00f;//清空PA10、PA9引脚模式 GPIOA->CRH|=0x000008b0;//PA10输入PA9输出// 4.通过在USART_CR1寄存器上置位UE位来激活USART USART1->CR1|=1<CR1&=~(1<CR2&=~(0x3<BRR=72000000/bps;// 8.设置USART_CR1中的TE位,发送一个空闲帧作为第一次数据发送。 USART1->CR1|=1<CR1|=1<<2;}

3. USART1串口底层发送数据函数

USART1串口数据发送函数(以数据帧格式发送):

配置步骤:

1.把发送的数据放入到USART_DR数据寄存器

2.判断USART_SR状态寄存器的TXE(发送数据寄存器空)位数据是否发送完成

代码示例:

/* USART1串口底层数据发送函数 形参:temp——>发送的数据*/void USART1_TX(u8 *temp){ while(*temp) { USART1->DR=*temp++; while(&(USART1->SR&1<<7)){} }}

测试USART1串口初始化函数和USART1串口底层发送函数

代码示例:

#include \"LED.h\"#include \"Delay.h\"#include \"SYSTICK.h\"#include \"BEEP.h\"#include \"KEY.h\"#include \"USART1.h\"int main(){ LED_Init();//LED灯初始化函数 BEEP_Init();//蜂鸣器初始化函数 KEY_Init();//按键初始化函数 USART1_Init(115200);//USART1串口1初始化函数 USART1_TX((u8 *)\"串口1初始化完成\\n\");//发送\"串口1初始化完成\"这句话 while(1) { }}

测试结果:

4. 串口读取/接收数据操作

操作步骤:

1. 首先判断USART1_SR寄存器中RXNE(读数据寄存器非空),置1表示收到数据,可以读出。置0表示数据没有收到;

2. 将收到数据返回给上位机终端显示

代码示例:

#include \"LED.h\"#include \"Delay.h\"#include \"SYSTICK.h\"#include \"BEEP.h\"#include \"KEY.h\"#include \"USART1.h\"int main(){ LED_Init();//LED灯初始化函数 BEEP_Init();//蜂鸣器初始化函数 KEY_Init();//按键初始化函数 USART1_Init(115200);//USART1串口1初始化函数 USART1_TX((u8 *)\"串口1初始化完成\\n\"); u8 dat=0; while(1) { if(USART1->SR&1<DR;//读取数据 USART1->DR=dat;//将读取的数据在上位机软件显示 } }}

上位机软件发送数据给USART1串口判断是否接收:

发送结果显示:

5. printf( )打印函数使用USART1底层实现 

在我们以后项目开发过程中会遇到各种各样的开发问题,使用printf( )函数可以让我们快速方便的查找问题!解决问题!下面是利用串口1实现printf( )函数的底层实现;

配置步骤:

1.在文件中查找函数fputc

2.创建printf( )打印函数

3.实现printf函数还需在keil v5中的魔法棒中第二个选项卡Target中勾选右上角的Use Micro LIB;

代码示例:

/* printf函数底层接口实现 形参:tx——发送的内容 注意:不需要声明哟!*/int fputc(int tx, FILE *stream){ USART1->DR=tx; while(!(USART1->SR&1<<7)) {} return tx;}

第三步操作:

测试printf( )函数实现代码示例:

#include \"USART1.h\"#include \"stdio.h\"int main(){ USART1_Init(115200);//USART1串口1初始化函数 printf(\"大河向东流哇\\n天上的星星参北斗哇\\n嘿嘿 参北斗哇\\n生死之交一碗酒哇\\n说走咱就走哇\\n你有我有全都有哇\\n嘿嘿 全都有哇\\n\"); while(1) { }}

测试结果

6. 显示USART1接收到的数据

代码示例:

#include \"stm32f10x.h\"#include \"Delay.h\"#include \"USART.h\"#include int main(){ USART1_Init(115200);//串口1初始化函数 USART1_TX((u8 *)\"串口1初始化成功\\n\"); u8 dat;//读取数据 u8 buffer[100];//接收数据的数组 u8 cnt=0;//下标 while(1) { if(USART1->SR&1<DR;//读取数据 buffer[cnt]=dat;//将读取的数据放入到数组中 if(dat == \'\\n\') { buffer[cnt-1]=\'\\0\';//上位机软件设置时以\\r\\n结尾。手动把\\r改成数组结束标准符 printf(\"buf=%s;\\tcnt=%d\\n\",buffer,cnt); cnt=0; } else cnt++; } }}

制作不易!喜欢的小伙伴给个小赞赞!喜欢我的小伙伴可以点关注!有不懂的地方和需要的资源随时问我哟!