STM32 串口通信实验

实验器材:F103开发板
在F103环境下进行UART通信实验和RS232通信实验

UART通信实验(通用异步收发器)

UART串口通信原理:

在这里插入图片描述

什么是串行通信?什么是异步通信?什么是全双工?
什么是串行通信
在这里插入图片描述

相较于串行通信还有一种并行通信(最常用还是串行)
在这里插入图片描述
图中可以看出串行通信的传输线有一根,而并行的线有多根,串行是一位一位的发送数据,而并行是多位多位的发送数据,好比单车道和多车道的区别,并行通信的传输速率要比串行高,那是不是并行传输要比串行传输要好?
非也,非也,并行通信存在多根线,线与线之间会存在数据的干扰,布线难度加大,资源浪费,常用的还是串行通信

什么是异步通信?

同步通信相比较与异步通信多了时钟总线,时钟总线的作用就是保证收发双方的时间同步,
而异步通信是如何做到收发双方数据同步?这里的UART处理是波特率的设置(ulBaud)
波特率保证了收发数据时间上的同步,每秒发送多少个数据,每秒接受多少个数据。
常见的有9600,115200……显而易见数值越大发送的越快。
但是发送越快可能会存在数据的丢失。
波特率: 是衡量资料传送速率的指标。表示每秒钟传送的符号数(symbol)。一个符号代表的信息量(比特数)与符号的阶数有关。例如传输使用256阶符号,每8bit代表一个符号,资料传送速率为120字符/秒,则波特率就是120baud,比特率是120*8=960bit/s。这两者的概念很容易搞错

什么是全双工通信?
单工通信:数据只能发送,不能接受
半双工:数据可以发送,可以接受,但是发送和接受不能同时进行(一般只有一条线数据传输)
全双工:数据可以发送,可以接收,并且可以同时进行(一般是有两条线来传输,TX,RX)

UART的通信过程

在这里插入图片描述

如图:
1.数据协议规定,在空闲状态下,UART为高电平状态,发送一位的起始位逻辑0代表通信的开始
2.接着是发送数据位,数据位由5-8位数据位一位奇偶校验组成
3.数据发送完成是停止位,代表一次通信的结束
4.数据发送完成后为空闲状态,即恢复为高电平状态,等待下一次的呼叫
(串口每次只能发送一个字节的数据,是为了减少传输中出现的错误,如果要发送多个字节的数据,则需要重复这一过程)

起始位: 先发出一个逻辑”0”的信号,表示传输字符的开始。

数据位: 数据位在起始位之后,它的个数可以是5-8位(先发低位后发高位)如:10101010,构成一个字符。通常采用ASCII码。从最低位开始传送,靠时钟定位。

奇偶校验位: 数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性(可有可无,只能校验,不能纠错)

停止位: 它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。 由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。

空闲位: 处于逻辑“1”状态,表示当前线路上没有数据传输。

波特率: 是衡量资料传送速率的指标。表示每秒钟传送的符号数(symbol)。一个符号代表的信息量(比特数)与符号的阶数有关。例如传输使用256阶符号,每8bit代表一个符号,资料传送速率为120字符/秒,则波特率就是120baud,比特率是120*8=960bit/s。这两者的概念很容易搞错。

实验功能:

如图所示:当我们连接好硬件后,打开串口通信软件设置好波特率等等,复位开发板
串口打印出请输入您的指令:………………
当我们输入0的时候开发板上的LED右移,LCD显示为LED右移颜色高亮,并且串口返回数据LED右移已打开………………
其他功能:
使用中断按键key1,key2,key3,key4操作LCD,并且如串口指令执行功能
key1,key3 菜单下滑
key2,key4菜单上滑

在这里插入图片描述

软件设计:

原理图:

在这里插入图片描述

uart.c文件

void USART2_Init(unsigned long ulBaud)
{
  GPIO_InitTypeDef GPIO_InitStruct;//定义结构体(GPIO,USART,NVIC)
  USART_InitTypeDef USART_InitStruct;
	NVIC_InitTypeDef NVIC_InitStruct;
	
  // 允许GPIOA和USART2时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
  // PA2-TX2复用推挽输出(端口配置)
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStruct);
  /* PA3-TX2浮空输入(复位状态,可以省略)
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStruct); */
  // 初始化USART2(波特率ulBaud,允许Rx和Tx,默认8个数据位,1个停止位,无校验)
  USART_InitStruct.USART_BaudRate = ulBaud;//波特率
  USART_InitStruct.USART_WordLength = USART_WordLength_8b;//数据位
  USART_InitStruct.USART_StopBits = USART_StopBits_1;//停止位
  USART_InitStruct.USART_Parity = USART_Parity_No;//(校验位:无)
  USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//设置收发模式
  USART_InitStruct.USART_HardwareFlowControl
    = USART_HardwareFlowControl_None;//硬件流控制:无
 USART_Init(USART2, &USART_InitStruct);//串口2初始化
 USART_Cmd(USART2, ENABLE);//使能USART2
 USART_ClearFlag(USART2,USART_FLAG_TC);//清除发送完成标志
	
	
    USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);//开启USART2接受中断
	NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;//主优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;//子优先级
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//中断使能
	NVIC_Init(&NVIC_InitStruct);//中断初始化
	
}
// 发送字符
unsigned char USART_SendChar(USART_TypeDef* USARTx, unsigned char ucChar)
{
  while(!USART_GetFlagStatus(USARTx, USART_FLAG_TXE));
  USART_SendData(USARTx, ucChar);
  return ucChar;
}
// 发送字符串
void USART_SendString(USART_TypeDef* USARTx, unsigned char* pucStr)
{
  while(*pucStr != '\0')
    USART_SendChar(USARTx, *pucStr++);
}
// 非阻塞接收字符
unsigned char USART_ReceiveChar_NonBlocking(USART_TypeDef* USARTx)
{
  if(USART_GetFlagStatus(USARTx, USART_FLAG_RXNE))
    return USART_ReceiveData(USARTx);
  else
    return 0;
}
// printf调用函数(使用MicroLIB)
int fputc(int ch, FILE *f)
{
  return(USART_SendChar(USART2, ch));
}

注:使用printf打印的时候需要在MDK上勾选Use Micor LIB
在这里插入图片描述

#include "key.h"
#include "led.h"
#include "lcd.h"
#include "stdio.h"
#include "usart.h"
#include "stm32f10x_exti.h"


void LCD_Proc(void);
void LED_Proc(void);
void Key_Init(void);
void LED_Control(uint16_t LED,uint8_t LED_Status);
void USART2_Init(unsigned long ulBaud);


uint32_t TimingDelay = 1;
unsigned char ucSec,ucLed=1;
unsigned long ulTick_ms;
int col_flag=0;
unsigned int i;


int main(void)
{
  SysTick_Config(72000);			// 定时1ms(HCLK = 72MHz)
  Key_Init();
  LED_Init();
  BUZ_Init();
  STM3210B_LCD_Init();				//LCD的初始化
	
  LCD_Clear(Cyan);				        //清屏配置颜色
  LCD_SetTextColor(White);		    //字体颜色
  LCD_SetBackColor(Cyan);	  	    //字体背景颜色
   
  LED_Control(LEDALL,0);//控制所有LED灯默认关闭(0关闭,1打开)
	USART2_Init(9600);       //串口初始化,设置波特率9600
	
	    USART_SendString(USART2,"请输入您的指令:\r\n");	
		USART_SendString(USART2,"   输入0:LED左移\r\n");	
		USART_SendString(USART2,"   输入1:LED右移\r\n");	
		USART_SendString(USART2,"   输入2:打开蜂鸣器\r\n");	
	    USART_SendString(USART2,"   输入3:关闭蜂鸣器\r\n\r\n");	
	      
  while(1)
  { 
   LCD_Proc();
   LED_Proc();
  }
  
 }
	
  
void LED_Proc(void)
{
	switch(col_flag)
	{
		case 1:
		  if(ulTick_ms > 300)      //0.3S延时
		  {
			ulTick_ms = 0;
			  
			ucLed >>= 1;
			if(ucLed == 0) 
				ucLed =0x80;           //LED右移函数
			LED_Disp(ucLed);
		  }
		  break;
			
			
		case 2:
		  if(ulTick_ms > 300)      //0.3S延时
		  {
			ulTick_ms = 0;
			  
			LED_Disp(ucLed);
			ucLed <<= 1;             //LED左移函数
			if(ucLed ==0)
				ucLed = 1;
		  }
		  break;
			
			
		case 3:
			LED_Control(LEDALL,0);
			GPIO_ResetBits(GPIOB,GPIO_Pin_4);//打开蜂鸣器
		  break;
		
		
		case 4:
			LED_Control(LEDALL,0);
			GPIO_SetBits(GPIOB,GPIO_Pin_4);
		
	}
	
}

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

LCD中文显示需要做字库,在fonts.h文件内

*************************************/
//LCD中文显示
void LCD_Proc(void)
{
      LCD_DisplayStringLine(Line1,"      19");
	  LCD_DisplayproHZ(Line1, 4, 0);
	  LCD_DisplayproHZ(Line1, 5, 1);
	  LCD_DisplayproHZ(Line1, 6, 2);   //嵌入式
	
	if(col_flag==1)
		LCD_SetBackColor(Blue);
		LCD_DisplayStringLine(Line3,"    1. LED");
        LCD_DisplayproHZ(Line3, 5, 4);
	    LCD_DisplayproHZ(Line3, 6, 5);   //右移
		LCD_SetBackColor(Cyan);

	if(col_flag==2)
		LCD_SetBackColor(Blue);
		
	
	  LCD_DisplayStringLine(Line5,"    2. LED");
	  LCD_DisplayproHZ(Line5, 5, 3);
	  LCD_DisplayproHZ(Line5, 6, 5);  //左移
	  LCD_SetBackColor(Cyan);

	if(col_flag==3)
	  LCD_SetBackColor(Blue);
	  LCD_DisplayStringLine(Line7,"    3.");
      LCD_DisplayproHZ(Line7, 3, 6);
      LCD_DisplayproHZ(Line7, 4, 7);
	  LCD_DisplayproHZ(Line7, 5, 8);
	  LCD_DisplayproHZ(Line7, 6, 9);  //蜂鸣器开
		LCD_SetBackColor(Cyan);
	if(col_flag==4)
		LCD_SetBackColor(Blue);
		LCD_DisplayStringLine(Line9,"    4.");
		LCD_DisplayproHZ(Line9, 3, 6);
		LCD_DisplayproHZ(Line9, 4, 7);
	    LCD_DisplayproHZ(Line9, 5, 8);
	    LCD_DisplayproHZ(Line9, 6, 10); //蜂鸣器关
		LCD_SetBackColor(Cyan);
	
 

	
}


//按键中断
void Key_Init(void)
{
	EXTI_InitTypeDef   EXTI_InitStructure;//定义结构体
	GPIO_InitTypeDef   GPIO_InitStructure;
	NVIC_InitTypeDef   NVIC_InitStructure; 	

	//时钟配置
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
  /* PA0和PA8浮空输入*/
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_8;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure); 
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0|GPIO_PinSource8);
  /* PB1和PB2浮空输入*/
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStructure); 
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1|GPIO_PinSource2);
	
	
     GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);//打开PA0中断连接
 	 EXTI_ClearITPendingBit(EXTI_Line0);//清除中断标志
 	 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource8);//打开PA8中断连接
	 EXTI_ClearITPendingBit(EXTI_Line8); 
	 GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);//打开PB1中断连接
	 EXTI_ClearITPendingBit(EXTI_Line1);
	 GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource2);//打开PB2中断连接
	 EXTI_ClearITPendingBit(EXTI_Line2);
	
  	EXTI_InitStructure.EXTI_Line = EXTI_Line0|EXTI_Line8|EXTI_Line1|EXTI_Line2;//选择中断线0,8,2,1
  	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//设置中断请求
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发  
  	EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能中断线
  	EXTI_Init(&EXTI_InitStructure);


    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组
		
		
  //PA0 
  	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//使能按键所在的外部中断通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢占优先级
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//子优先级
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure);

	//PA8
    NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  	NVIC_Init(&NVIC_InitStructure);

	//  PB1 
  	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =2;
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  	NVIC_Init(&NVIC_InitStructure);

	// PB2
  	NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  	NVIC_Init(&NVIC_InitStructure);

}




//中断服务函数
void EXTI0_IRQHandler(void)   //PA0
{  
	 for(i=0x5ffff; i>0; i--);//延时
	
	if(EXTI_GetFlagStatus(EXTI_Line0)!=RESET)
	{
		EXTI_ClearFlag(EXTI_Line0);
		
				 col_flag++;
			if(col_flag>4)
				 col_flag=1;
			
	}
}

void EXTI9_5_IRQHandler(void)    //PA8
{   
	for(i=0x5ffff; i>0; i--);//延时
	if(EXTI_GetFlagStatus(EXTI_Line8)!=RESET)
	{
		EXTI_ClearFlag(EXTI_Line8);
			   col_flag--;
			if(col_flag<1)
				 col_flag=4;
			
	}
}


void EXTI1_IRQHandler(void)  //PB1
{  
	 for(i=0x5ffff; i>0; i--);//延时
	
	if(EXTI_GetFlagStatus(EXTI_Line1)!=RESET)
	{
		EXTI_ClearFlag(EXTI_Line1);
		
				 col_flag++;
			if(col_flag>4)
				 col_flag=1;
			
	}
}



void EXTI2_IRQHandler(void)  //PB2
{   for(i=0x5ffff; i>0; i--);//延时
	if(EXTI_GetFlagStatus(EXTI_Line2)!=RESET)
	{
		EXTI_ClearFlag(EXTI_Line2);
			   col_flag--;
			if(col_flag<1)
				 col_flag=4;
			
	}
}

//串口中断服务函数
void USART2_IRQHandler(void)    
{
  uint8_t temp;
  if(USART_GetFlagStatus(USART2,USART_IT_RXNE)!=0)
  { 
		temp=USART_ReceiveData(USART2);
		USART_SendData(USART2,temp);
		
		switch(temp)
		{
			
			case'0':
				col_flag=1;
			USART_SendString(USART2,":LED右移已打开\r\n\r\n");
       
		
			  break;
				
			case'1':
				col_flag = 2;	
				USART_SendString(USART2,":LED左移已打开\r\n\r\n");		
			  
				break;
			
			case'2':
				//col_flag = 3;	//太吵了,实验自己打开
				USART_SendString(USART2,":蜂鸣器已打开\r\n\r\n");	
        
       	break;
			
			case'3':
				col_flag = 4;
				USART_SendString(USART2,":蜂鸣器已关闭\r\n\r\n");	
        break;
		
	}
		
  }

}


void SysTick_Handler(void)
{
  ulTick_ms++;
  if(ulTick_ms%1000 == 0) ucSec+=0;          
}


LCD,LED,key初始化函数,以及中文显示请下载工程查看

完整工程下载

选择第11个工程

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值