(个人杂记)第九章 串口实验2

4.4.1端口复用和重映射

内置外设:集成在单片机内部的可以被指令直接控制的外部设备,如串口控制模块,SPI模块,I2C模块,A/D模块,PWM模块,CAN模块,EEPROM,比较器模块等端口复用功能
What:(正点原子p126)STM32有很多的内置外设,这些外设的外部引脚都是与GPIO复用的。也就是说,一个GPIO如果可以复用为内置外设的功能引脚,那么当这个GPIO作为内置外设使用的时候,就叫做复用。
个人理解:内置外设的接口和GPIO的接口是一致的,我们可以操作GPIO的接口来控制内置外设的功能。实际上给GPIO的接口赋予了多个功能,通过I/O的工作模式来切换不同形态。
Can: 提高复用,节省资源
Use: 典型使用的有
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
具体可参考《STM32中文参考手册V10》P109起

这里我们用到的是USART1,PA9、PA10引脚默认是串口1的使用,即端口复用
在这里插入图片描述


复用端口初始化步骤

  • 使能端口和串口的时钟。这里用到USART1和两个IO
RCC_APB2PriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Priph_USART1,ENABLE);
  • 端口模式配置。我们可以理解为设置模式就可切换功能,具体如何配置,查看《STM32中文参考手册V10》P110(上图有贴出来)
    在这里插入图片描述

4.4.2端口重映射

What:(正点原子p127)为了使不同器件封装的外设I0功能数量达到最优,可以把一些复用功能重新映射到其他些引脚.上。STM32中有很多内置外设的输入输出引脚都具有重映射(remap)的功能。在STM32中引入了外设引脚重映射的概念,即一个外设的引脚除了具有默认的端口外,还可以通过设置重映射寄存器的方式,把这个外设的引脚映射到其它的端口。
个人理解:将内置外设的输入输出端口改变到其他端口
Can: 每个内置外设都有若干个输入输出引脚,一般这些引脚的输出端口都是固定不变的,为了让设计工程师可以更好地安排引脚的走向和功能,
Use: 简单的讲就是把管脚的外设功能映射到另一个管脚,但不是可以随便映射的,具体对应关系《STM32中文参考手册V10》的P116 页“8. 3复用功能和调试配置”有讲解。

在这里插入图片描述

端口重映射步骤如下

  • 使能GPIOB和串口时钟(同复用一样)
  • 使能AFIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
  • 开启重映射
GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);//接口——引脚重映射功能(接口——重映射——串口名,能)

串口设置步骤

  1. 串口时钟使能,GPIO时钟使能
  2. 串口复位(可以省略)
  3. GPIO 端口模式设置
  4. 串口参数初始化
  5. 开启中断并且初始化NVIC (如果需要开启中断才需要这个步骤)
  6. 使能串口
    USART_Cmd(USART1,ENABLE);
  7. 编写中断处理函数

串口状态:USART_GetFlagStatus(USART1,USART_FLAG_EXNE);//RXNE寄存器是否非空
发送完成:USART_GetFlagStatus(USART1,USART_FALG_TC)//TC发送完成

注意:必须在usart.h中设置EN_USART1_RX为1,复用的IO在逻辑分析窗口是无法显示的

设计案例并实现

实验要求

将前面3章的知识运用起来,设计一个多功能按键选择实验

  • 利用3个按键,KEY0、KEY1、WK_UP分别控制,DS0、DS1、BEEP
  • 串口通信,分别控制三个按钮是否有效
  • 通讯头0xC5 + 命令(0xa0、0xb1、0xab、0xcc)
  • 命令解释:0xa0打开KEY0,0xb1打开KEY1,0xab打开WK_UP,0xcc关闭所有按键功能
  • 将接收到的命令发回给上位机表示收到,Ack_Cmd()
  • 如果没有检测到通讯头,就重新接收

实验部分代码

/*******usart.c********/
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
		{
		Res =USART_ReceiveData(USART1);	//读取接收到的数据			
		if((USART_RX_STA&0x8000)==0)//接收未完成
		{
			if(USART_RX_STA==0)
			{
				if(Res!=0xC5)
				{
					USART_RX_STA=0;
				}else{
					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res;//c5
					USART_RX_STA++;//1
				}
			}		
			else if(USART_RX_STA>0){				
				if(USART_RX_STA>3)
				{
					USART_RX_STA=0;
				}
				if(USART_RX_STA==3)
				{
					USART_RX_STA|=0x8000;
				}
				USART_RX_BUF[USART_RX_STA&0X3FFF]=Res;
				USART_RX_STA++;
			}
		} 
     } 
/************main.c**************/
u8 Ack[3];
u16 t=0;
u16 len;
void Ack_Cmd(void)
{	
	Ack[0]=0xC5;
	Ack[1]=USART_RX_BUF[1];  
	for(t=0;t<2;t++)
	{
		USART_SendData(USART1, Ack[t]);//向串口4发送数据
		while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
	}
}
 int main(void)
 {		
  
	u16 key;	
	u16 temp0=0,temp1=0,temp2=0;
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 //串口初始化为115200
 	LED_Init();			     //LED端口初始化
	KEY_Init();          //初始化与按键连接的硬件接口
	BEEP_Init();		 //蜂鸣

 	while(1)
	{
		key = KEY_Scan(0);
		switch(key)
		{
			case KEY0_PRES: 
			{
				if(temp0){
					delay_ms(10);
					LED0=~LED0;
				}
				break;
			}
			case KEY1_PRES:
			{
				if(temp1){
					delay_ms(10);
					LED1=~LED1;
				}
				break;
			}				
			case WKUP_PRES:
			{
				if(temp2){
					delay_ms(10);
					BEEP=~BEEP;
				}
				break;
			}					
		}
		if(USART_RX_STA&0x8000)//接收完成的判断
		{	
			USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);		
			delay_ms(20);
 			Ack_Cmd();
			delay_ms(20);
			if(USART_RX_BUF[1]==0xa0) temp0=1;
			else if(USART_RX_BUF[1]==0xb1) temp1=1;
			else if(USART_RX_BUF[1]==0xab) temp2=1;
			else if(USART_RX_BUF[1]==0xcc) {temp0=0;temp1=0;temp2=0;}
			USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开启接收中断
			USART_RX_STA=0;
		}
	}	 
 }

在这里插入图片描述

实验现象

一开始三个按键都是无效的,通过串口发送正确格式的命令(C5开头+一个字节的命令+调试助手自带的空格\换行),分别发送对应按键命令后,得到命令答复,再次按下按键,可以发现led灯可以亮灯\熄灭,蜂鸣器响\不响,再发送0xcc命令后,所有按键控制的功能都失效了。

实验不足

按下按键,灯会有颤动虽然加了delay_ms延缓,其次命令返回有事不准又是准,观察得出可能是缓存的问题,上个命令下次才出现。

总结

初次学习很多都不是很理解,不过向前学不应该停下纠结,想必随着后来接触越来越多,以往不懂的地方也能潜移默化的明白了。个人综合前面学习知识设计的案例,可能存在不足,大家也可以自己设计案例

文章参考文献均来自正点原子哦

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UART1_RX_STA是一个状态标志,用于表示UART1接收数据的状态。根据引用\[1\]和引用\[3\]的内容,可以看出UART1_RX_STA是一个16位的变量,其中0~14位用来存储接收到的数据个数,15位和16位用来表示接收是否完成。当接收到数据时,UART1_RX_STA会自增,表示接收到的数据个数增加了。当接收到的数据以0x0d 0x0a结尾时,UART1_RX_STA的15位会被置为1,表示接收完成。在主函数中,可以通过判断UART1_RX_STA的值来判断接收是否完成,并读取UART1_RX_BUF\[\]数组中的数据。需要注意的是,在处理完串口数据后,需要将UART1_RX_STA清零。 #### 引用[.reference_title] - *1* [浅谈USART_RX_STA各位的描述以及是如何实现数据接收的](https://blog.csdn.net/JackCrum/article/details/99864683)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [(个人杂记)串口中断(关于USART_RX_STA的详细分析)](https://blog.csdn.net/canola_flowers/article/details/126178175)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [2021-10-31](https://blog.csdn.net/W2020492669/article/details/121062355)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值