STM32学习笔记六——GPIO模拟USART

0、摘要

在实际开发当中会遇到串口不够的情况,此时我们可以通过GPIO模拟USART。

    IO口模拟串口的思路也比较简单,一切按照串口协议进行操作即可。
    对于发送,计算好不同波特率对应的延时时间进行数据发送。
    对于接收,稍微复杂。通过外部中断检测接收管脚的下降沿,检测到起始信号后开启定时器,定时器按照波特率
设定好时间,每隔一段时间进入定时器中断接收数据,完成一个字节后关闭定时器。

1、新建工程,勾选相应的库

 选中:CMSIS>CORE;Device>Startup;>StdPeriph Drivers>EXTI;>Framework;>GPIO;>RCC;>TIM;等

2、程序分析

IO口初始化配置

//输出管脚配置
void GPIO_Configuration(void)
{
   GPIO_InitTypeDef GPIO_InitStructure;
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
   GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//输入管脚及中断配置
void GPIO_Configuration(void)
{
   GPIO_InitTypeDef GPIO_InitStructure;
   EXTI_InitTypeDef EXTI_InitStruct;
   NVIC_InitTypeDef NVIC_InitStructure;

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;    //上拉输入 ,IO口默认是高电平
   GPIO_Init(GPIOA, &GPIO_InitStructure);
   GPIO_SetBits(GPIOA,GPIO_Pin_10);//保持高电平

   EXTI_InitStruct.EXTI_Line=EXTI_Line10; 
   EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
   EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;    //下降沿中断
   EXTI_InitStruct.EXTI_LineCmd=ENABLE;
   EXTI_Init(&EXTI_InitStruct);
   NVIC_InitStructure.NVIC_IRQChannel=EXTI15_10_IRQn; //外部中断,边沿触发
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
   NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
   NVIC_Init(&NVIC_InitStructure);
}

发送函数

//发送1个字节
void IO_TXD(u8 ch)
{
   u8 i = 0; 
   GPIO_ResetBits(GPIOC,GPIO_Pin_9);
   delay_us(BuadRate_9600);
   for(i = 0; i < 8; i++)
   {
     if(ch&0x01)
       GPIO_SetBits(GPIOC,GPIO_Pin_9); 
     else 
       GPIO_ResetBits(GPIOC,GPIO_Pin_9);
    delay_us(BuadRate_9600);
    ch = ch>>1;
   }
   GPIO_SetBits(GPIOC,GPIO_Pin_9); 
   delay_us(BuadRate_9600);
}

//发送字符串
void USART_Send(u8 *buf, u8 len)
{
   u8 t;
   for(t = 0; t < len; t++)
   {
     IO_TXD(buf[t]);
   }
}

设置枚举变量,这里考虑到USART共有10个bit数据。

enum{
 COM_START_BIT, //起始位
 COM_D0_BIT,
 COM_D1_BIT,
 COM_D2_BIT,
 COM_D3_BIT,
 COM_D4_BIT,
 COM_D5_BIT,
 COM_D6_BIT,
 COM_D7_BIT,
 COM_STOP_BIT, //结束位
};

接收程序可以使用软件延时的方式(但是不推荐),也可使用定时器的方式进行接收。

  • 软件延时方式
void EXTI15_10_IRQHandler(void) 
{
	enum stat recvStat = COM_STOP_BIT; //定义初始为停止位
	if(EXTI_GetITStatus(EXTI_Line10)!=RESET)   //检查外部中断是否产生了
	{ 
		if(!GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_10)) //检测引脚高低电平,如果是低电平,则说明检测到起始位
		{
		Delay(0x33A); //延时 0x432 约等于104us
		if(recvStat == COM_STOP_BIT)
		{
			recvStat = COM_START_BIT; //此时的状态是起始
			while(recvStat!= COM_STOP_BIT) // 循环到停止位
			{
				recvStat++; // 改变状态
				if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_10)) //‘1’
				{
					recvData |= (1 <<(recvStat -1));
				}
				else
				{
					recvData &= ~(1 << (recvStat -1));
				} 
				Delay(0x33A);
			}
		}
	}
	EXTI_ClearITPendingBit(EXTI_Line10); //清除EXTI_Line10中断挂起标志位
	} 
}
  • 定时器方式
void EXTI15_10_IRQHandler(void)
{	
	if(EXTI_GetFlagStatus(EXTI_Line14) != RESET)	
	{		
		if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_10) == 0) 		
		{			
			if(recvStat == COM_STOP_BIT)			
			{				
				recvStat = COM_START_BIT;				
				TIM_Cmd(TIM4, ENABLE);			
			}		
		}	
	EXTI_ClearITPendingBit(EXTI_Line14);	
	}
} 

void TIM4_IRQHandler(void)
{
	if(TIM_GetFlagStatus(TIM4, TIM_FLAG_Update) != RESET)	
  	{		
  		TIM_ClearITPendingBit(TIM4, TIM_FLAG_Update);			 
  		recvStat++;		
  		if(recvStat == COM_STOP_BIT)		
  		{			
  			TIM_Cmd(TIM4, DISABLE);			
  			USART_buf[len++] = recvData;				
  			return;		
  		}		
  		if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_10))	//接收为高电平	
  		{			
  			recvData |= (1 << (recvStat - 1));		
  		}
  		else
  		{			
  			recvData &= ~(1 << (recvStat - 1));		
  		}	  
  	}		
 }

3、参考链接

USART简介

USART模拟

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值