• (个人杂记)第九章 串口实验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);
    
    • 1
    • 端口模式配置。我们可以理解为设置模式就可切换功能,具体如何配置,查看《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);
    
    • 1
    • 开启重映射
    GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);//接口——引脚重映射功能(接口——重映射——串口名,能)
    
    • 1

    串口设置步骤

    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++;
    			}
    		} 
         } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    /************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;
    		}
    	}	 
     }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    在这里插入图片描述

    实验现象

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

    实验不足

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

    总结

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

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

  • 相关阅读:
    2021年认证杯SPSSPRO杯数学建模A题(第一阶段)医学图像的配准全过程文档及程序
    2023研究生数学建模E题保姆级思路 出血性脑卒中临床智能诊疗
    bat程序小功能
    基于SSM的图书管理借阅系统设计与实现
    基于Vue+Vue-Router+Vuex+SPA+element ui admin实现在线教育前端
    基于Docker部署GeoWebCache(离线地图)
    多个串的最长公共子序列
    2140. 解决智力问题;1401. 圆和矩形是否有重叠;901. 股票价格跨度
    WebSocket(简单体验版)
    佳期投资专场——第321场LeetCode周赛题解
  • 原文地址:https://blog.csdn.net/canola_flowers/article/details/126153934