最近项目中STM32的串口资源紧张,于是使用IO口进行模拟串口,现进行整理记录。
实现思路
IO口模拟串口的思路也比较简单,一切按照串口协议进行操作即可。
对于发送,计算好不同波特率对应的延时时间进行数据发送。
对于接收,稍微复杂。通过外部中断检测接收管脚的下降沿,检测到起始信号后开启定时器,定时器按照波特率设定好时间,每隔一段时间进入定时器中断接收数据,完成一个字节后关闭定时器。
测试Demo说明
TXD : PC13
RXD : PB14
波特率:9600 ,1-8-N
Demo功能
接收11个数据,然后把接收到的数据发送出去。
程序实现
#define OI_TXD PCout(13)
#define OI_RXD PBin(14)
#define BuadRate_9600 100
u8 len = 0; //接收计数
u8 USART_buf[11]; //接收缓冲区
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,
};
u8 recvStat = COM_STOP_BIT;
u8 recvData = 0;
void IO_TXD(u8 Data)
{
u8 i = 0;
OI_TXD = 0;
delay_us(BuadRate_9600);
for(i = 0; i < 8; i++)
{
if(Data&0x01)
OI_TXD = 1;
else
OI_TXD = 0;
delay_us(BuadRate_9600);
Data = Data>>1;
}
OI_TXD = 1;
delay_us(BuadRate_9600);
}
void USART_Send(u8 *buf, u8 len)
{
u8 t;
for(t = 0; t < len; t++)
{
IO_TXD(buf[t]);
}
}
void IOConfig(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC, ENABLE); //使能PB,PC端口时钟
//SoftWare Serial TXD
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC,GPIO_Pin_13);
//SoftWare Serial RXD
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
EXTI_InitStruct.EXTI_Line = EXTI_Line14;
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_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =2;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void TIM4_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //时钟使能
//定时器TIM4初始化
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ClearITPendingBit(TIM4, TIM_FLAG_Update);
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //TIM4中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级1级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //从优先级1级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
}
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
delay_init();
IOConfig();
TIM4_Int_Init(107, 71); //1M计数频率
while(1)
{
if(len > 10)
{
len = 0;
USART_Send(USART_buf,11);
}
}
}
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetFlagStatus(EXTI_Line14) != RESET)
{
if(OI_RXD == 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(OI_RXD)
{
recvData |= (1 << (recvStat - 1));
}else{
recvData &= ~(1 << (recvStat - 1));
}
}
}
Demo下载
Demo工程下载地址github。
https://github.com/TonyIOT/SoftWareSerial.git
上一篇:关于STM32 利用IO口模拟串口实现数据通信
下一篇:stm32 浮点数问题
推荐阅读最新更新时间:2024-11-22 23:56
设计资源 培训 开发板 精华推荐
- LTC3110EFE 2A 双向降压-升压型 DC/DC 稳压器的典型应用电路
- C8051F560DK,C8051F555 8051 MCU 工业应用开发系统
- 使用 NXP Semiconductors 的 MC9S08JM60CLHE 的参考设计
- AR0134CSSM00SUEAH3-GEVB:1.2 MP Sunex DSL945D 1/3" iBGA CIS HB
- DI-146 - 35W液晶显示器电源
- LTC3447EDD 演示板,DFN Vccc=2.5V-5.5Vin 中的 I2C 可控降压稳压器
- EVAL-AD7766EDZ-U1,AD7766/AD7767评估板,24位,10mW,128KHz,24位ADC
- #第七届立创电赛#usb电压电流表
- RD-438,将 FSFR2100 电源开关用于辅助电源应用的参考设计
- NN机器人--微型视觉控制振动机器人