飞道的博客

实验四、串口通信实验

328人阅读  评论(0)

实验四、串口通信实验

​ 自律 学习 坚强 ,拒绝迷茫。

作者:行走的皮卡丘

时间:2021/4/4

喜欢就去追,这个红灯等不到,说不定下一个红灯等到了,嘻嘻!!!!!!!


一、 实验目的

  • 1、 掌握STM32串口通信原理。

  • 2、 学习编程实现STM32的UART通信。

二、 实验设备

硬件:

​ PC机 一台

​ STM32开发板 一套

软件:

​ MDK V4.0 一套

​ Windows 7 一套

​ 调试助手 一套

三、 实验原理

3.1、状态寄存器USART_SR及函数

第5、6位 RXNETC

  • RXNE(读数据寄存器非空),当该位被置1的时候,就是提示已经有数据被接收到了,并且可以读出来了。

  • TC(发送完成),当该位被置位的时候,表示USART_DR内的数据已经被发送完成了。

在固件库函数里面,读取串口状态的函数是:

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx,  uint16_t  USART_FLAG )

这个函数的第二个入口参数非常关键,它是标示我们要查看串口的哪种状态,比如上面讲解的RXNE(读数据寄存器非空)以及TC(发送完成)。

例如:要判断读寄存器是否非空(RXNE),操作库函数的方法是:

USART_GetFlagStatus(USART1,USART_FLAG_RXNE);

要判断发送是否完成(TC),操作库函数的方法是:

USART_GetFlagStatus(USART1,USART_FLAG_TC);

3.2、USATR1 发送一个字节

/****************************************************************

USATR1 发送一个字节

功能:发送一个字节的数据

入口参数:发送到数据

出口参数:无

*****************************************************************/

void Send_OneByte(uint8_t onebyte)

{
   

  while(RESET == USART_GetFlagStatus(USART1, USART_FLAG_TC));//等待发送完毕USART_SendData(USART1, onebyte);	

}

3.3、接收一个字节的数据

/****************************************************************

功能:接收一个字节的数据

入口参数:无

出口参数:返回收到的数据

*****************************************************************/

uint8 rxdata;//存储收到的数据
uint8 Receive_OneByte(void)
{
   
	if(USART_GetITStatus(USART1, USART_IT_RXNE)!= RESET)//串口收到数据
	{
   
        rxdata = USART_ReceiveData(USART1);
    }
	return rxdata;
}

3.4、串口编程为如下步骤:

//1) 串口时钟使能, GPIO 时钟使能

//配置时钟,由于使用串口是在复用IO口,需要打开串口时钟和相应的IO口时钟。


//2) GPIO 端口模式设置

//串口相应的IO口需要配置,输出口配置成复用推挽输出,输出速度根据需要配置,输入口配置为悬空输入。
    

//3) 串口参数初始化,使能串口。(***\*串口调试助手 与之一致\**** )

 USART_InitTypeDef   USART_InitStructure;  

 USART_InitStructure.USART_BaudRate = ***\*115200\****;  //波特率

 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位  

 USART_InitStructure.USART_StopBits = USART_StopBits_1;  //1位停止位

 USART_InitStructure.USART_Parity = USART_Parity_No;  //无奇偶校验位

 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  //无硬件数据流控制  

 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  

 //收发模式 
 USART_Init(USART1, &USART_InitStructure );  //初始化串口1

 //USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启接收中断。若无中断,该项不需要

 USART_Cmd(USART1, ENABLE);           //使能串口1 


//4) 初始化 NVIC且开启中断(若开启中断才需要该步骤)

  NVIC_InitTypeDef   NVIC_InitStructure;  

  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;  

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;

  //抢占优先级0,级别可自己设定 ,下面的子优先级可自定

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;    //子优先级2  

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  

  //IRQ通道使能  
  NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器  
 

//5) 编写中断处理函数 (有中断才需要该步骤)

四、实验内容

1、用STM32设计一个与计算机进行串口通讯的实验。STM32向PC发送 123ABC ,用串口调试助手 显示出来,用查询方式完成。

2、用STM32设计一个与计算机进行串口通讯的实验。PC向STM32发送 456789 ,STM32接收后,将 每位数值+3 发送给PC,用 串口调试助手显示出来,用中断方式完成。

3、用STM32设计一个与计算机进行串口通讯的实验,利用PC控制LED的亮灭。

1)PC向STM32发送 A ,控制LED1,LED2,LED3同时亮灭,间隔时间0.5S,同时在 串口调试助手显示LED1,LED2,LED3同时亮灭”。

2)PC向STM32发送 B ,控制LED1,LED2,LED3正向流水亮灭,间隔时间1S,同时在串口调试助手显示LED1,LED2,LED3正向流水亮灭”。

3)PC向STM32发送 C ,控制LED1,LED2,LED3反向流水亮灭,间隔时间2S,同时在 串口调试助手显示LED1,LED2,LED3反向流水亮灭”。

4、利用定时器结合串口实现 电子时钟的功能。功能如下:

1)定时器完成 1S 的定时。

2)串口调试助手*上显示时间,格式参考如下 12:34:56 ,每秒递增。串口调试助手每2秒刷新一次。

③在LCD上显示时间,格式参考如下 12:34:56 ,每秒递增。例程可参考 FSMC-液晶显示-英文的配套例程。

4.1、用STM32设计一个与计算机进行串口通讯的实验。STM32向PC发送 123ABC,用串口调试助手显示出来,查询方式完成。(代码:实验4-1)

usart.c函数

#include "sys.h"
#include "usart.h"	  
 
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{
    
	int handle; 

}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{
    
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{
         
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;      
	return ch;
}

//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误   	
u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
u16 USART_RX_STA=0;       //接收状态标记	  
  
void uart_init(u32 bound){
   
  //GPIO端口设置
  GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
  
	//USART1_TX   GPIOA.9
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
   
  //USART1_RX	  GPIOA.10初始化
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  

  //Usart1 NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
   //USART 初始化设置

	USART_InitStructure.USART_BaudRate = bound;//串口波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式

  USART_Init(USART1, &USART_InitStructure); //初始化串口1
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
  USART_Cmd(USART1, ENABLE);                    //使能串口1 

}

void USART1_IRQHandler(void)                	//串口1中断服务程序
	{
   
	u8 Res;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
		{
   
		Res =USART_ReceiveData(USART1);	//读取接收到的数据
		
		if((USART_RX_STA&0x8000)==0)//接收未完成
			{
   
			if(USART_RX_STA&0x4000)//接收到了0x0d
				{
   
				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
				else USART_RX_STA|=0x8000;	//接收完成了 
				}
			else //还没收到0X0D
				{
   	
				if(Res==0x0d)USART_RX_STA|=0x4000;
				else
					{
   
					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
					USART_RX_STA++;
					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
					}		 
				}
			}   		 
     } 

} 

usart.h函数

#ifndef __USART_H
#define __USART_H
#include "stdio.h"	
#include "sys.h" 

#define USART_REC_LEN  			200  	//定义最大接收字节数 200
#define EN_USART1_RX 			1		//使能(1)/禁止(0)串口1接收
	  	
extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u16 USART_RX_STA;         		//接收状态标记	
//如果想串口中断接收,请不要注释以下宏定义
void uart_init(u32 bound);

#endif

main函数

#include "delay.h"
#include "sys.h"
#include "usart.h"

/**************************************************
* Function       main
* @author        行走的皮卡丘
* @date          2021/4/4
* @brief        
* @param[in]    
* @param[out]    void
* @retval        void
* @par History   无
* TXD PA.9
* RXD PA.10
*************************************************/
 int main(void)
 {
   		
 	u16 t;  
	u8 data[10]="123ABC";
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 //串口初始化为115200
 	while(1)
	{
   	   
		printf("\r\nSTM32发送的消息为:  ");
		for(t=0;t<sizeof(data);t++)
		{
   
			USART_SendData(USART1, data[t]);//向串口1发送数据
			while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
		}
		printf("\r\n");//插入换行
		delay_ms(1000);
	}	 
 }

4.2、用STM32设计一个与计算机进行串口通讯的实验。PC向STM32发送 456789 ,STM32接收后,将 每位数值+3 发送给PC,用 串口调试助手 显示出来,用中断方式完成。(代码:实验4-2)

main函数

#include "sys.h"
#include "usart.h"
/**************************************************
* Function       main
* @author        行走的皮卡丘
* @date          2021/4/4
* @brief        
* @param[in]    
* @param[out]    void
* @retval        void
* @par History   无
* TXD PA.9
* RXD PA.10
*************************************************/

 int main(void)
 {
   		
	char String[]="0123456789ABCDEFG";
 	u8  i;	 
  u8 data;
	u16 len;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 //串口初始化为115200
 	while(1)
	{
   
		if(USART_RX_STA&0x8000)
		{
   			
			len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
			USART_RX_BUF[len] = 0;
			printf("\r\n PC发送的消息为:%s\r\n",USART_RX_BUF);
			printf(" STM32发送的消息为:");
			for(i = 0;i < len;i++)
			{
   
				data=String[ USART_RX_BUF[i] - 48 + 3 ];
				printf("%c",data);
			}
			printf("\r\n");//插入换行
			USART_RX_STA=0;
		}
	}	 
 }

4.2.3、用STM32设计一个与计算机进行串口通讯的实验,利用PC控制LED的亮灭。(代码:实验4-3)

1)PC向STM32发送 A ,控制LED1,LED2,LED3同时亮灭,间隔时间0.5S,同时在 串口调试助手显示LED1,LED2,LED3同时亮灭”。

2)PC向STM32发送 B ,控制LED1,LED2,LED3正向流水亮灭,间隔时间1S,同时在 串口调试助手显示LED1,LED2,LED3正向流水亮灭”。

3)PC向STM32发送 C ,控制LED1,LED2,LED3反向流水亮灭,间隔时间2S,同时在 串口调试助手显示LED1,LED2,LED3反向流水亮灭”。

#include "delay.h"
#include "sys.h"
#include "usart.h"


/**************************************************
* Function       main
* @author        行走的皮卡丘
* @date          2021/4/4
* @brief        
* @param[in]    
* @param[out]    void
* @retval        void
* @par History   无
* TXD PA.9
* RXD PA.10
*************************************************/

#define LED1 PBout(0)
#define LED2 PCout(4)
#define LED3 PCout(3)

void LED_Init(void)
{
   
	GPIO_InitTypeDef GPIO_InitStr;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);//   
	
	
	GPIO_InitStr.GPIO_Mode=GPIO_Mode_Out_PP;//推挽
	GPIO_InitStr.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStr.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStr);  // PB0   LED1
	
	GPIO_InitStr.GPIO_Pin=GPIO_Pin_4;
	GPIO_Init(GPIOC,&GPIO_InitStr);  // PC4   LED2
	GPIO_InitStr.GPIO_Pin=GPIO_Pin_3;
	GPIO_Init(GPIOC,&GPIO_InitStr);  // PC3   LED3

	GPIO_SetBits(GPIOB,GPIO_Pin_0); 
	GPIO_SetBits(GPIOC,GPIO_Pin_4); 
	GPIO_SetBits(GPIOC,GPIO_Pin_3); 
}


 int main(void)
 {
   		
 	u16 i=0;  
	u16 len;	
	u16 data;
	 
	LED_Init();			     //LED端口初始化
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 //串口初始化为115200
 	
 	while(1)
	{
   
	    if(USART_RX_STA&0x8000)  //接收数据
			{
   
					len = USART_RX_STA&0x3f; 
					for(i = 0;i < len; i++)
					{
   
						data = USART_RX_BUF[i];
						while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);	
					}
					USART_RX_STA = 0;	
					
					if(data == 'A')
					{
   
							data = 0;
							printf("LED1,LED2,LED3同时亮灭\r\n");
							LED1=1; LED2=1; LED3=1;
							while(USART_RX_STA==0)
							{
   
								LED1=~LED1; LED2=~LED2; LED3=~LED3;
								delay_100ms(5);
							}				
					}
					
					if(data == 'B')
					{
   
							data = 0;
							printf("LED1,LED2,LED3正向流水亮灭\r\n");
							while(USART_RX_STA==0)
							{
   
								LED1=1; LED2=1; LED3=0;
								delay_100ms(10);
								LED1=1; LED2=0; LED3=1;
								delay_100ms(10);				
								LED1=0; LED2=1; LED3=1;
								delay_100ms(10);				
							}				
					}
					
					if(data == 'C')
					{
   
							data = 0;
							printf("LED1,LED2,LED3反向流水亮灭\r\n");
							LED1=1; LED2=1; LED3=1;
							while(USART_RX_STA==0)
							{
   
								LED1=0; LED2=1; LED3=1;
								delay_100ms(20);
								LED1=1; LED2=0; LED3=1;
								delay_100ms(20);				
								LED1=1; LED2=1; LED3=0;
								delay_100ms(20);
							}				
					}				
			}			
	}	 
}

4.4、利用定时器结合串口实现 电子时钟的功能。(代码:实验4-4)

  • 定时器完成 1S 的定时。

  • 形参设置为arr=9999,psc=7199即可

  • 串口调试助手上显示时间,格式参考如下 12:34:56 ,每秒递增。串口调试助手每2秒刷新一次。

  • 主函数中的死循环,其中flay在定时器2的中断中累加,即一秒以1累加。

  • 在LCD上显示时间,格式参考如下 12:34:56,每秒递增。例程可参考FSMC-液晶显示-英文的配套例程。

main函数

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "timer.h"
#include "lcd.h" 

/**************************************************
* Function       main
* @author        行走的皮卡丘
* @date          2021/4/4
* @brief        
* @param[in]    
* @param[out]    void
* @retval        void
* @par History   无
* TXD PA.9
* RXD PA.10
*************************************************/



 int main(void)
 {
   		
	ILI9341_Init();
	ILI9341_GramScan( 6 );  //设置默认扫描方向,其中 6 模式为大部分液晶例程的默认显示方向  
	LCD_SetColors(GBLUE,BLACK); 		//设置颜色
	ILI9341_Clear(0,0,LCD_X_LENGTH,LCD_Y_LENGTH);
	LCD_SetFont(&Font16x24);
	LCD_SetTextColor(GREEN);   //设置文本颜色
	 
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 //串口初始化为115200
 	LED_Init();			     //LED端口初始化
	TIM2_Int_Init(9999,7199); //一秒一次中断  72 000 000 /7200=10000  10000/10000=1hz 1/1hz=1s
	 
 	while(1)
	{
   
		if( flay==2 )
		{
   
			flay = 0;
		  printf("%s\r\n",TimeStr);
		}
		
	}	 
 }

四、实验总结

加油!!!行走的皮卡丘!!!!

实验四代码下载链接


转载:https://blog.csdn.net/weixin_44908159/article/details/115426607
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场