IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32USART[直接用寄存器] -> 正文阅读

[嵌入式]STM32USART[直接用寄存器]

我们之前学到的都只是对单片机简单的操作,单片机和上位机没有任何通信,等学完这一篇后,你就可以通过串口来和上位机进行联系,实现数据的交流。

一、串行通信

按照串行数据时钟控制,可以分为异步和同步通信。

1、异步

在异步通信中,数据是以字符为单位组成字符帧发送的,发送端和接收端可以由各自独立时钟来控制收发。在异步通信中,接收端通过字符帧格式来判断发送端的发送时间和结束时间。
(1)字符帧格式
起始位,数据位(低位在前),奇偶校验位,停止位`

-----------------------------------------------------------------
| 0 | D0 | D1 | D2 | D3| D4 | D5 | D6 | D7 | 0/1 | 1 |...|0|D0|..
-----------------------------------------------------------------

起始位:位于帧开头,占1位,为低电平0,表示发送端开始发送一帧数据
数据位:可取5位,6位,7位,8位,低位在前,高位在后
奇偶校验位:选择校验方式,有奇校验和偶校验
停止位:位于帧结尾,为高电平1,表示发送端发送完一帧数据

在串行通信中,相邻一帧数据可以有空闲位,也可以没有空闲位。
(2)波特率
每秒传送二进制数码的位数,也叫比特数,单位 bps;波特率和字符的实际传输速率不同,字符的实际传输速率是每秒内所传字符帧的帧数,和字符帧格式有关。
注意:在收发时,必须要保证波特率一致,就好比打电话,一个反应慢,另一个还说话快,这样在传递消息时,就会数据丢失,所以要设定波特率一致

异步通信的优点是不需要传送同步时钟,字符帧长度不受限制,设备简单,而缺点也很明显,起始位和停止位会大大降低传输效率。

2、同步

同步通信是一种连续串行传送数据的通信方式,一次通信只传输一帧信息。这里的信息帧通常有若干个数据字符,信息帧均由同步字符、数据字符和校验字符CRC三部分组成。在同步通信中,同步字符可以采用统一的标准格式,也可以自定义。

3、通信方式

通信方式有三种:单工,半双工,全双工。
单工:只能往一个方向传送

-----              -----
|   | -----------> |   |
|   |              |   |
-----              -----

半双工:接收或发送要分时进行

-----              -----
|   | ----t1-----> |   |
|   | <---t2------ |   |
-----              -----

全双工:可以同时发送或接收

-----              -----
|   | ----t1-----> |   |
|   | <---t1------ |   |
-----              -----

二、USART

在这里插入图片描述
图中可以看到,STM32F103ZET6支持五路串口,有三个USART和两个UART。
USART:通用同步和异步收发器
UART:通用异步收发器
两者在做异步时没有任何区别,只不过USART是增强版,多了一个同步收发。

串口硬件连接:
USART1:TX:PA9,RX:PA10
USART2:TX:PA2,RX:PA3
USART3:TX:PB10,RX:PB11
在使用串口时,这些GPIO口要设置为复用模式

三、USART工作原理

在这里插入图片描述
:数据从RX口进入,先到接收移位寄存器,这个寄存器一位一位将数据移到接收数据寄存器RDR里,然后通过读操作读取数据。
:先将数据存放到TDR数据寄存器里,再由移位寄存器发送给TX口。

四、USART寄存器

1、USART_SR(状态寄存器)

在这里插入图片描述
在这里插入图片描述

这个寄存器只介绍6位和5位

  • 6位:TC:当该位被置位的时候,表示 USART_DR 内的数据已经被发送完成了。如果设置了这个位的中断,则会产生中断。该位也有两种清零方式:(1)读 USART_SR,写USART_DR。(2)直接向该位写 0。

  • 5位:RXNE:当该位被置 1 的时候,就是提示已经有数据被接收到了,并
    且可以读出来了。这时候我们要做的就是尽快去读取 USART_DR,通过读 USART_DR 可以将该位清零,也可以向该位写 0,直接清除。

2、USART_DR(数据寄存器)

在这里插入图片描述
在这里插入图片描述DR寄存器用来保存接收到的数据和要发送的数据,这是一个双寄存器,包含了 TDR 和 RDR。当向该寄存器写数据的时候,串口就会自动发送。

3、USART_BRR(波特率寄存器)

在这里插入图片描述
上文说的异步通信里最重要的波特率就是由这个寄存器设置的

  • 15:4位:定义了USARTDIV的整数部分
  • 3:0位:定义了USARTDIV的小数部分
    在这里插入图片描述
    我们常用的波特率为115200,那么计算方式如下:
    USARTDIV=72000000/(115200*16)=39.0625
    整数部分:39
    小数部分:0.0625
    转换为16进制:整数部分:0x27,小数部分:0x1
    那么 USART1_BRR=0x0271 ,就可以设置USART1串口的波特率为115200HZ。

4、USART_CR1(控制寄存器1)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 13位:USART使能
  • 12位:定义字长
  • 6位:该位发送完成中断使能
  • 5位:接收缓冲区非空中断使能
  • 3位:发送使能
  • 2位:接收使能

五、代码

1、usart.c

#include "stm32f10x.h"
#include "led.h"
#include "stdio.h"
#include "usart.h"
#include "delay.h"
//菜单
void menu()
{
	printf("\r\n-----------菜单--------\r\n");
	printf("\r\n1、红灯翻转\r\n");
	printf("\r\n2、绿灯翻转\r\n");
	printf("\r\n3、蜂鸣器翻转\r\n");
	printf("\r\n---请选择要进行的操作----\r\n");	
}
//串口中断配置
void USART1_Init_NVIC(void)
{
		RCC->APB2ENR|=1<<0;			//开启复用时钟
		SCB->AIRCR|=0x05FA0500; 	//写入钥匙和分组2
		NVIC->ISER[1]|=0x0000020;	//USART1(37)中断使能
		NVIC->IP[37]|=15<<4;       //USART1 抢3 占3
}
//串口查询式发送
void  USART1_PUT(unsigned char C)
{
	while((!(USART1->SR&(1<<6)))&&(!(USART1->SR&(1<<7))));
	USART1->DR=C;
}
//重定向fputc函数
int fputc(int ch, FILE *f)
{ 
	USART1_PUT(ch);
	return ch;
}
//串口初始化
void USART1_Init(void)
{
	RCC->APB2ENR|=1<<2;			//PA使能
	RCC->APB2ENR|=1<<14;		//串口使能
	
	RCC->APB2RSTR|=1<<14;       //复位串口1
	RCC->APB2RSTR&=~(1<<14);	//停止复位	 
	
	GPIOA->CRH&=0xFFFFF00F;
	GPIOA->CRH|=0x00000490;		//PA9复推,PA10浮空
	
	USART1->BRR|=0x0271;		//15200
	USART1->CR1&=~(1<<12);	    //8位数据位,1位停止位
	USART1->CR1&=~(1<<10);		//无校验
	
	USART1->CR1|=1<<3;			//发送
	USART1->CR1|=1<<2;			//接收
	
	USART1->CR1|=1<<5;			//使能接收中断
	USART1->CR1|=1<<13;			//串口使能
	USART1_Init_NVIC();         //串口中断配置
}
//---------------------接收中断服务函数--------------------------
void USART1_IRQHandler()
{
	unsigned int num;
	num=USART1->DR;    //读取DR寄存器
	USART1_PUT(num);   //串口查询式发送
	switch(num)
	{
		case	49:    //发送1时,红灯翻转  49为1的ASCll码
			LED0=!LED0;
			printf("\r\n红灯翻转成功\r\n");
			menu();
			break;
		case	50:    //发送2时,绿灯翻转
			LED1=!LED1;
			printf("\r\n绿灯翻转成功\r\n");
			menu();
			break;
		case	51:    //发送3时,蜂鸣器翻转
			BEEP=!BEEP;
			printf("\r\n蜂鸣器翻转成功\r\n");
			menu();
			break;
	}
}
/*有一点要注意,我们学习C语言时,用的printf函数是把数据打印在屏幕上,
现在我们是要将数据打印给串口,所以我们要将printf函数重定向
int fputc(int ch, FILE *f)
{ 
	USART1_PUT(ch);
	return ch;
}
然后要使用 printf 函数,我们依然要加头文件 stdio.h
在keil5魔术棒中,在Target选项卡里,勾选Use MicroLlB
之后我们就可以使用 printf 来打印数据

2、usart.h

#ifndef __USART_H
#define __USART_H
void USART1_Init(void);  //串口初始化
void USART1_Init_NVIC(void);  //串口中断配置
void USART1_PUT(unsigned char C);  //查询式发送
void menu(void);  //菜单
#endif

3、led.c

#include "stm32f10x.h"
#include "led.h"
//LED初始化
void LED_Init()
{
	RCC->APB2ENR|=1<<3;			//APB2-GPIOB外设时钟使能	
	RCC->APB2ENR|=1<<6;			//APB2-GPIOE外设时钟使能
	
	GPIOB->CRL&=0xFF0FFFFF;		//设置位清零	
	GPIOB->CRL|=0x00200000;		//PB5推挽输出
	GPIOB->ODR|=1<<5;			//设置初始灯为灭
	
	GPIOE->CRL&=0xFF0FFFFF;		//设置位清零
	GPIOE->CRL|=0x00200000;  	//PE5推挽输出
	GPIOE->ODR|=1<<5;			//设置初始灯为灭	
	
	GPIOB->CRH&=0xFFFFFFF0;		//引脚初始化
	GPIOB->CRH|=0x00000002;		//PB8推挽
	GPIOB->ODR&=~(1<<8);		//蜂鸣器不工作
}

4、led.h

#ifndef __LED_H
#define __LED_H
#include "stm32f10x.h"
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 
 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入
//位带定义
#define LED0 	PBout(5)	//红灯
#define LED1 	PEout(5)	//绿灯
#define BEEP  PBout(8)	//蜂鸣器

void LED_Init(void);	//初始化		
#endif

5、delay.c

#include "stm32f10x.h"
#include "delay.h"
void System_clock(unsigned char PLL)
{
	unsigned int Clock_OK;
	RCC->CR|=1<<16;			    //开启HSE高速外部时钟
	while(!(RCC->CR&(1<<17)));	//等待HSE开启成功
	RCC->CFGR|=4<<8;	//0x00000400 AHB不分频;APB2不分频;APB1二分频
	FLASH->ACR|=0x2;	//FLASH缓冲
	RCC->CFGR|=1<<16;	//PREDIV1输出作为PLL输入时钟
	PLL=PLL-2;		    //选择PLL倍频2--9
	RCC->CFGR|=PLL<<18;	//PLL九倍频输出
	RCC->CR|=1<<24;		//PLL使能
	while(!(RCC->CR&(1<<25)));	//等待PLL使能成功
	RCC->CFGR|=2<<0;			//选择PLL为系统时钟
	do						  //等待系统时钟设置成功
	{
		Clock_OK=RCC->CFGR&0x0c;
	}
	while(Clock_OK!=0x08);
}
//设置完成后系统时钟:SYSCLK=72MHZ;AHB:HCLK=72MHZ;APB2:PCLK=72MHZ;APB1:PCLK1=36MHZ

//滴答定时器us延时
void SysTick_us(unsigned int time)
{
	unsigned long num;
	SysTick->VAL=0;				//计数器清零
	SysTick->LOAD=9*time;		//重装载计数值
	SysTick->CTRL|=1<<0;	    //定时器使能,打开定时器
	do
	{
		num=SysTick->CTRL;
	}
	while((num&0x01)&&!(num&(1<<16)));//等待计数器到0
	SysTick->CTRL&=~(1<<0);			  //关闭计数器
	SysTick->VAL=0;					  //计数器清零
}

//滴答定时器ms延时
void SysTick_ms(unsigned int time)
{
	unsigned long num;
	SysTick->VAL=0;						//计数器清零
	SysTick->LOAD=9000*time;		    //重装载计数值
	SysTick->CTRL|=1<<0;				//定时器使能,打开定时器
	do
	{
		num=SysTick->CTRL;
	}
	while((num&0x01)&&!(num&(1<<16)));//等待计数器到0
	SysTick->CTRL&=~(1<<0);			  //关闭计数器
	SysTick->VAL=0;					  //计数器清零
}

6、delay.h

#ifndef __DELAY_H
#define __DELAY_H
void System_clock(unsigned char PLL);  //系统时钟初始化
void SysTick_us(unsigned int time);    //微秒级延时
void SysTick_ms(unsigned int time);    //毫秒级延时
#endif

7、main.c

#include "stdio.h"
#include "delay.h"
#include "led.h"
#include "usart.h"
int main(void)
{
	System_clock(9); //系统时钟九倍频,72MHZ
	LED_Init();		//LED初始化
	USART1_Init();  //串口初始化
	menu();         //菜单
	while(1)
	{
		SysTick_ms(500); //延时
	}
}

六、效果展示

在这里插入图片描述
先看一下我们需要用的软件,叫XCOM,页面如上所示,串口选择里设置好我们编辑代码时所设置的串口参数,之后就可以用来查看串口发送的数据,也可以向串口发送数据。
在这里插入图片描述
程序下载成功,会出现如图的菜单,要求我们选择一个选项
在这里插入图片描述
我们在消息发送区输入1,点击发送,可以看到消息接收区,弹出了1,并紧跟着显示红灯翻转成功,大家可以观察自己的开发板,红灯会发生翻转,输入2绿灯翻转,输入3蜂鸣器翻转。
在这里插入图片描述
在这里插入图片描述
由于蜂鸣器不好展示效果,所以大家可以自行尝试。

7、总结

此文章只配置了USART1,关于其他两个,USART2和USART3,大家可以自己配置一下,但是要注意波特率的计算,这两个串口在低速总线上,大家要万分注意,还有就是对于GPIO口复用配置,此文代码中,led.c,delay.c,前面几篇有详细讲解,不会的可以查阅。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-09-09 11:56:09  更:2021-09-09 11:56:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 0:34:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码