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<<2;//开启PA时钟;
  RCC->APB2ENR|=1<<14;//开启USART1时钟
//  2. 对串口1模块开启复位时钟,在取消复位;
  RCC->APB2RSTR|=1<<14;//开启USART1复位时钟,复位这一步可以省略配置USART1步骤
  RCC->APB2RSTR&=~(1<<14);//取消复位时钟,关闭复位
//  3. 配置GPIO模式
  GPIOA->CRH&=0xfffff00f;//清空PA10、PA9引脚模式
  GPIOA->CRH|=0x000008b0;//PA10输入PA9输出
//  4.通过在USART_CR1寄存器上置位UE位来激活USART
  USART1->CR1|=1<<13;
//  5.编程USART_CR1的M位来定义字长。
  USART1->CR1&=~(1<<12);
//  6.在USART_CR2中编程停止位的位数。
  USART1->CR2&=~(0x3<<12);
//  7.利用USART_BRR寄存器选择要求的波特率。
  USART1->BRR=72000000/bps;
//  8.设置USART_CR1中的TE位,发送一个空闲帧作为第一次数据发送。
  USART1->CR1|=1<<3;
//  9.设置USART_CR1的RE位。激活接收器,使它开始寻找起始位。
  USART1->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<<5)
    {
      dat=USART1->DR;//读取数据
      USART1->DR=dat;//将读取的数据在上位机软件显示
    }
  }
}

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

发送结果显示:

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

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

配置步骤:

1.在<stdio.h>文件中查找函数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 <stdio.h>

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<<5)
      {
        dat=USART1->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++;
      }
   }
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李永奉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值