【No6~STM32】串口通信

(1)关于RS-232

在串口通信中RS-232 电平标准的信号不能直接
被控制器直接识别,所以这些信号会经过一个“电平转换芯片”转换成控制器能识别的
“TTL 校准”的电平信号,才能实现通讯

控制器一般使用 TTL 电平标准,所以常常会使用 MA3232 芯片对 TTL 及 RS-232
电平的信号进行互相转换。

TTL标准:逻辑1:2.4V到5V

                 逻辑0:0到0.5V

RS-232 :逻辑1:-15V到-3V

                 逻辑0:+3v~+15v

在旧式的台式计算机中一般会有 RS-232 标准的 COM 口(也称 DB9 接口),接线口以针式引出信号线的称为公头,以孔式引出信号线的称为母头.

接收数据 RXD DTE-DCE Receive Data,数据接收信号,即输入。

发送数据 TXD DTE-DCE Transmit Data,数据发送信号,即输出。两个
设备之间的 TXD 与 RXD 应交叉相连。

数据设备
(DCE) 就绪DSR DT-DCE Data Set Ready,数据发送就绪,用于 DCE 告知对方本机是否处于待命状态

公头5GND对应母头5GND

(2)串口异步和同步区别

stm32中将sclk(时钟)关闭就为异步通信,开启时为同步传输。异步通信电平间隔不固定,同步固定。

(3)波特率

以两个通讯设备之间需要约定好波特率,即每个码元的长度,以便对信号进行解码,常见的波特率为
4800、9600、115200 等

(4)起始和停止信号
串口通讯的一个数据包从起始信号开始,直到停止信号结束。数据包的起始信号由一个逻辑 0 的数据位表示。

数据包的停止信号可由 0.5、1、1.5 或 2 个逻辑 1 的数据位表示,只要双方约定一致即可。

(5)有效数据

在数据包的起始位之后紧接着的就是要传输的主体数据内容,也称为有效数据,有效数据的长度常被约定为 5、6、7 或 8 位长。
 

(6)数据校验

在有效数据之后,有一个可选的数据校验位。校验方法有奇校验(odd)、偶校验(even)、0 校验(space)、1 校验(mark)以及无校验(noparity)。

奇校验要求有效数据和校验位中“1”的个数为奇数。

注:0 校验是不管有效数据中的内容是什么,校验位总为“0”,1 校验是校验位总为
“1”

在无校验的情况下,数据包中不包含校验位

(7)USART

(1)USART 满足外部设备对工业标准 NRZ 异步串行数据格式的要求,并且使用了小数波特率发生器,可以提供多种波特率,使得它的应用更加广泛。USART 支持同步单向通信和半双工单线通信;USART 支持使用 DMA,可实现高速数据通信。

(2)应用:

 USART 在 STM32 应用最多莫过于“打印”程序信息,一般在硬件设计时都会预留一
个 USART 通信接口连接电脑,用于在调试程序是可以把一些调试信息“打印”在电脑端
的串口调试助手工具上,从而了解程序运行是否正确、指出运行出错位置等等

ps:STM32 的 USART 输出的是 TTL 电平信号,若需要 RS-232 标准的信号可使用
MAX3232 芯片进行转换。

(3)相关寄存器

TX:发送数据输出引脚。
RX:接收数据输入引脚。

SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。

数据寄存器:USART 数据寄存器(USART_DR):只有低 9 位有效,并且第 9 位数据是否有效要取决于
   USART 控制寄存器 1(USART_CR1)的 M 位设置,当 M 位为 0 时表示 8 位数据字长,当 M
位为 1 表示 9 位数据字长,我们一般使用 8 位数据字长。

USART_DR 实际是包含了两个
寄存器,一个专门用于发送的可写 TDR,一个专门用于接收的可读 RDR。往 USART_DR 写入数据会自动存储在 TDR 内;当进行读取操作时,向 USART_DR读取数据会自动提取 RDR 数据。

TDR 和 RDR 都是介于系统总线和移位寄存器之间。串行通信是一个位一个位传输的,
发送时把 TDR 内容转移到发送移位寄存器,然后把移位寄存器数据每一位发送出去,接收
时把接收到的每一位顺序保存在接收移位寄存器内然后才转移到 RDR。

(4)一个字符帧发送需要三个部分:起始位+数据帧+停止位,起始位是一个位周期的低电平,数据帧就是我们要发送的 8 位或 9 位数据,停止位是一定时间周期的高电平,可选 0.5 个、1 个、1.5 个和 2 个停止位。

(5)标志位:

TE 发送使能
TXE 发送寄存器为空,发送单个字节的时候使用
TC 发送完成,发送多个字节数据的时候使用
TXIE 发送完成中断使能

TE 置 1 之后,发送器开始会先发送一个空闲帧(一个数据帧长度的高电平),接下来就可以往 USART_DR 寄存器写入要发送的数据

写入最后一个数据后,需要等待 USART 状态寄存器(USART_SR)的 TC 位为 1,表示数据传输完成。

USART_CR1 寄存器的 TCIE 位置 1,将产生中断。

RX:接受使能:USART_CR1 寄存器的 RE 位置 1,使能 USART 接收,接收器在 RX 线开始搜索起始位

RXNE:读数据寄存器非空//数据接收完成后就把接收移位寄存器数据移到 RDR 内,并把 USART_SR 寄存器的 RXNE 位置1,

RXNEIE:发送完成中断使能

ps:

OVER8 位设置为 1 采用 8 倍过采样,
即用 8 个采样信号采样一位数据;如果 OVER8 位设置为 0 采用 16 倍过采样,即用 16 个采
样信号采样一位数据,8倍比16倍更快,16倍比8倍更精准。

接收数据时如果出现奇偶校验位验证失败,会见 USART_SR 寄存
器的 PE 位置 1,并可以产生奇偶校验中断

(6)串口中断请求:

发送数据寄存器为空 中断标志TXE    中断使能TXEIE

发送完成 TC TCIE

准备好读取接收到的数据 RXNE RXNEIE

奇偶校验错误 PE PEIE

USART 初始化结构体
1 typedef struct {
2 uint32_t USART_BaudRate; // 波特率
3 uint16_t USART_WordLength; // 字长
4 uint16_t USART_StopBits; // 停止位
5 uint16_t USART_Parity; // 校验位
6 uint16_t USART_Mode; // USART 模式
7 uint16_t USART_HardwareFlowControl; // 硬件流控制
8 } USART_InitTypeDef;

USART_BaudRate:波特率设置。一般设置为 2400、9600、19200、115200。

USART_WordLength:数据帧字长,可选 8 位或 9 位。它设定 USART_CR1 寄存
器的 M 位的值。如果没有使能奇偶校验控制,一般使用 8 数据位;如果使能了奇
偶校验则一般设置为 9 数据位。

USART_StopBits:停止位设置,可选 0.5 个、1 个、1.5 个和 2 个停止位,

USART_Parity : 奇 偶 校 验 控 制 选 择 , 可 选 USART_Parity_No( 无校验 ) 、
USART_Parity_Even( 偶校验 ) 以 及 USART_Parity_Odd( 奇校验 )。

USART_Mode:USART 模式选择,有 USART_Mode_Rx 和 USART_Mode_Tx,
允许使用逻辑或运算选择两个,它设定 USART_CR1 寄存器的 RE 位和 TE 位。

利用 USART 实现开发板与电脑通信,需要用到一个 USB 转 USART 的 IC,我们选
择 CH340G 芯片来实现这个功能。

 

二:程序设计

bsp_USART.h

#ifndef BSP_USART_H
#define BSP_USART_H
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_usart.h"
#include 
#define SIZE 50000

extern void usart1_init(void);
extern uint8_t usart_receivebyte(USART_TypeDef* USARTx);
extern  void usart_Sendbyte(USART_TypeDef* USARTx, uint8_t tem);
extern void tem_DM2_Config(void);
#endif

bsp_USART.c

#include "bsp_usart.h"
uint16_t SendBuff[SIZE];

void usart1_init(void)
{
     //结构体声明
	
	GPIO_InitTypeDef GPIO_InitStruct;
	//结构体初始化
	USART_InitTypeDef USART_InitStruct;
	
	//void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
	//void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct)
	//开启GPIOA时钟开启usart1时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	
	//配置GPIO A9和A10复用
	 
	 GPIO_InitStruct.GPIO_OType= GPIO_OType_PP;//推挽模式
	 GPIO_InitStruct.GPIO_PuPd=  GPIO_PuPd_UP;//上拉
	 GPIO_InitStruct.GPIO_Speed=GPIO_Fast_Speed;//50Mhz
	
	
	
  GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;//复用模式
	GPIO_PinAFConfig( GPIOA, GPIO_PinSource9,GPIO_AF_USART1);//连接 PXx 到 USARTx_Tx*
	GPIO_Init(GPIOA, &GPIO_InitStruct);//初始化结构体
	
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;
	GPIO_PinAFConfig( GPIOA, GPIO_PinSource10,GPIO_AF_USART1);//连接 PXx 到 USARTx_Rx*
	GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	
	
	//在配置USART1 1位停止位 8位数据位 无校验位 波特率115200
	
		USART_InitStruct.USART_BaudRate=115200;
	USART_InitStruct.USART_StopBits=USART_StopBits_1 ;
	USART_InitStruct.USART_WordLength=USART_WordLength_8b;
	USART_InitStruct.USART_Parity=USART_Parity_No;//无校验位
	 USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流控制:不使用硬件流
	
	//使能发送和接受
 USART_InitStruct.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;
    //放入结构体初始化
		USART_Init(USART1, &USART_InitStruct);
	
	//开启串口功能
  USART_Cmd( USART1,ENABLE);

}

主函数:

#include "stm32f4xx.h"
#include "bsp_usart.h"
#include "stm32f4xx_usart.h"
#include "bsp_led.h"
#include 
#include "bsp_exit.h"
#include "bsp_key.h"
extern uint16_t SendBuff[SIZE];
uint8_t data;
void delay_ms(unsigned int xms)
{
  unsigned int j;
	for(;xms>0;xms--)
	for(j=500;j>0;j--);

}
int main(void)
{
	uint16_t i;
  LED_GPIO_Config();
	 usart1_init();
	 key_Config();

while(1)
	{
		
        USART_SendData( USART1, 'b');//串口不断发送b
//	
//	    if(USART_ReceiveData( USART1)=='a')//电脑接受到a
	  {
	    GPIO_SetBits(GPIOC , GPIO_Pin_1);
	  }	
		 if(USART_ReceiveData( USART1)=='b')
	  {
	    GPIO_SetBits(GPIOC , GPIO_Pin_2);
	  }	
		 if(USART_ReceiveData( USART1)=='c')
	  {
	    GPIO_SetBits(GPIOC , GPIO_Pin_3);
    	  }	
    		 if(USART_ReceiveData( USART1)=='d')
     	  {
	        GPIO_SetBits(GPIOC , GPIO_Pin_4);//按下按键abcd 4个灯全亮
	      }	
	  
  

}


 

三 重定义printf和scanf

int fputc(int ch ,FILE *f)//重定义Printf到串口后才能使用printf
{
 USART_SendData(USART1, (uint8_t)ch);//发送一个字节到串口
	while(USART_GetFlagStatus( USARTx, USART_FLAG_TXE)==RESET);//等待发送完毕,当发送标志位为1时发送完毕,没有为0一直等待
		return ch;
	

}

//重定义scanf getchar函数到串口
//int fgetc(FILE *f)
//{
// 
//	while(USART_GetITStatus( USART1, USART_IT_TXE)==RESET);//等待输入数据标志位为1结束输入
//	return (int) USART_ReceiveData( USARTx);



//}
#include "stm32f4xx.h"
#include "bsp_usart.h"
#include "stm32f4xx_usart.h"
#include "bsp_led.h"
#include 
#include "bsp_exit.h"
#include "bsp_key.h"
extern uint16_t SendBuff[SIZE];
uint8_t data;
void delay_ms(unsigned int xms)
{
  unsigned int j;
	for(;xms>0;xms--)
	for(j=500;j>0;j--);

}
int main(void)
{
	uint16_t i;
  LED_GPIO_Config();
	 usart1_init();
	 key_Config();

 ch=getchar();
printf("接收到字符:%c\n",ch);



}

四:回调实验

#include "stm32f4xx.h"
#include "bsp_usart.h"
#include "stm32f4xx_usart.h"
#include "bsp_led.h"
#include 
#include "bsp_exit.h"
#include "bsp_key.h"
extern uint16_t SendBuff[SIZE];
uint8_t data;
void delay_ms(unsigned int xms)
{
  unsigned int j;
	for(;xms>0;xms--)
	for(j=500;j>0;j--);

}
int main(void)
{
	uint16_t i;
  LED_GPIO_Config();
	 usart1_init();
	 key_Config();

//当按键1按下时为0发送字符a同时点亮c口led1
 if(key_Scan( GPIOA,GPIO_Pin_0)==Key_OFF)//
	{
	  USART_SendData (USART1, 'a');
	  GPIO_SetBits(GPIOC , GPIO_Pin_1);
	}
//按下按键2发送串口1接受的数据(由串口助手接受并发送)
	if(key_Scan( GPIOC,GPIO_Pin_13)==Key_OFF)	
	{
	
	   
	   GPIO_SetBits(GPIOC , GPIO_Pin_2);
		USART_SendData (USART1, USART_ReceiveData( USART1));//发送串口接受到的数据
	}
		





}
///***°´按键检测*****printf***/
//		
//		if(key_Scan( GPIOA,GPIO_Pin_2)==Key_OFF)
//		{
//		   printf("\r\n·串口ð\r\n");
//	     GPIO_SetBits(GPIOC , GPIO_Pin_3);
//		
//		}		

五.回调实验

自定义一个串口发送和接受程序

void usart_Sendbyte(USART_TypeDef* USARTx, uint8_t tem)
{
 USART_SendData(USART1, tem);
 while(USART_GetFlagStatus( USART1, USART_FLAG_TXE)==RESET);//等标志位为1退出
//USART_FLAG_TXE发送缓冲区空标志:说明可以往数据寄存器写入数据了,不代表数据发送完成
}
//TXE 位由硬件置 1,它表示:
// 数据已从 TDR 移到移位寄存器中且数据发送已开始。
//TDR 寄存器为空。
///USART_DR 寄存器中可写入下一个数据,而不会覆盖前一个数据

uint8_t usart_receivebyte(USART_TypeDef* USARTx)
{
 uint8_t temp = 0;
	
 while(USART_GetFlagStatus( USART1, USART_FLAG_RXNE)==RESET);//RXNE接受数据寄存器非空标志位
//RXNE 位置 1。这表明移位寄存器的内容已传送到 RDR。也就是说,
//已接收到并可读取 数据(以及其相应的错误标志)
	temp = (int) USART_ReceiveData( USARTx);//从RDR读取数据
	USART_ClearFlag(USART1, USART_FLAG_RXNE);//RXNE 位必须在结束接收下一个字符前清零,以 
避免发生上溢错误。 
 return temp;
}
//上溢错误
//如果在 RXNE 未复位时接收到字符,则会发生上溢错误。RXNE 位清零前,数据无法从移位 
//寄存器传送到 RDR 寄存器。

主函数:

while(1)
	{
		/***********/
//		//printf("\r\n·¢ËÍ'a'µÆÁÁ·¢ËÍ'b'µÆÃð\r\n");
//		data=usart_receivebyte(USART1);//»Øµ÷ʵÑé

//	  switch(data)
//	  {
//	   	case 65 : USART_SendData (USART1, 'a');//接受到'a'的ascll码
//		  break;
//	  
//	
//	  }

注意查看参考手册串口状态寄存器章节

你可能感兴趣的:(stm32)