STM32F103C8T6使用普通IO口模拟串口收发(使用定期器-非阻塞的模拟)

导:

由于项目系统功能版本升级,需要开发一个带有串口收发的功能,但是硬件串口已经全部使用,发现还剩余部分普通gpio口可以使用,故打算采用软件模拟的方法实现该功能;

很久以前使用过51单片机来实现过类似功能,现在首次使用stm32来实现该功能;先借鉴一些网上的demo;

产品的代码初始框架不是我自己搭建的,下回轮到我来搭,一定一定用操作系统来完成,要不然资源的配置,考虑太多,真的麻烦死了;

参考:https://blog.youkuaiyun.com/yunjie167/article/details/79808464

1.阻塞的通讯

阻塞式通讯

51单片机,是没有操作系统的,并且定时器也是非常的有限的;所以再模拟iic通讯,或者模拟SPI,或者模拟串口uart通讯的时候,通讯是需要delay来延时(delay函数)的位置;延时函数往往是让系统空闲下来等待做不其他事情,很浪费系统的时间资源(这种等待占用了系统时间做“无用之事”,具“阻塞”作用);比如下方这个:使用定时器来计时!

{这个算是稍微高级一点的延迟处理(比单纯的i--好),这个只要将其优先级别放到最低,既可实现不影响中断的处理!}

2 非阻塞式通讯-发送操作

就是我通讯需要的延时不占用系统空闲时间:她需要通讯时,正常通讯,当到达该延时的时刻时,把cpu交给其他任务执行(执行其他任务也需要耗费一些时间的),到继续通讯后,自己得到获取处理权限,继续执行。。。

这是很多操作系统可以完成最基本功能;

由于我的代码框架已经基本固定死了,现在在单片机用基本定时器来完成这样的事情。。。。即完成非阻塞式通讯!

(1)定时器开启如下:

(2)调用发送函数:

UART4_Send_Buf(...);//注意STM32F103C8t6是没有串口4的!!!这是虚拟串口!!

(3)调用的发送函数里面开启了定时器,所以接下来将在定时期中断中进行发送操作

发送函数模拟了串口的时序:开始-发送-结束

发送完一个字节,然后从缓冲区callback(),调用下一个字节进行传输!

代码段如下:

static void send_remain_byte(void)
{
	if(VirtualUart.send_cnt>=VirtualUart.send_max)
	{
		VirtualUart.send_flag=0;	//发送完毕
	}
	else
	{
		VirtualUart.TXREG=VirtualUart.sendbuff[VirtualUart.send_cnt++];		
//		Tx_Pin=0; 			//产生START信号
	}
}

/**************************实现函数********************************************
*函数原型:		void UART4_Send_Buf(unsigned char *buf,unsigned char len)
*功  能:		通过模拟出来的串口-UART4 发送几个字节 的数据
unsigned char *buf  存放数据的数组指针
unsigned char len   要发送的字节数
*******************************************************************************/
void UART4_Send_Buf(unsigned char *buf,unsigned char len)
{
	unsigned char i ;
	for(i=0;i<len;i++,buf++)
	{
		VirtualUart.sendbuff[i]=*buf;
	}
	VirtualUart.send_cnt=0;//清除所得的数据大小
	VirtualUart.send_max=len;//长度
	VirtualUart.send_flag=1;//开始发生
	VirtualUart.send_mode=1;//模式为非阻塞方式
	TIM4->CR1|=0x01;    //使能定时器4
	flag_firstBitGet=1;
}
//TIM4定时器里调用
static u8 tim_send_byte(void (*Callback)(void))
{
	static int sendidx=0;
	if(flag_firstBitGet)
	{
		flag_firstBitGet=0;
		if(Callback!=NULL)			  //还有数据-->有多个字节要发送,调用回调函数继续发送下一个字节
			Callback();
		else
			VirtualUart.send_flag=0;//没数据了
	}
	if(sendidx==0)
	{
		sendidx++;
		Tx_Pin=0; 			//产生START信号
	}
	else	if(sendidx<=8)					//DATA 1,2,3...8
	{
		sendidx++;
		Tx_Pin=VirtualUart.TXREG&0x01;
		VirtualUart.TXREG>>=1;	
	} else if(sendidx==9) 
	{ 			//STOP
		Tx_Pin=1;
		sendidx++;
	} 
	else if(sendidx==10) 
	{				//STOP的发送完毕了
		sendidx=0;
				
		if(Callback!=NULL)			  //还有数据-->有多个字节要发送,调用回调函数继续发送下一个字节
			Callback();
		else
			VirtualUart.send_flag=0;//没数据了
		
		return 0;//返回0-完整的一个字节传输完成
	}
	
	return 1;	//返回1-正在传输字节过程中-busy
}
//定时器4中断服务程序
void TIM4_IRQHandler(void)   //TIM4中断
{
	if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)  //检查TIM4更新中断发生与否
	{
		tim4Counts++;
		TIM_ClearITPendingBit(TIM4, TIM_IT_Update);  //清除TIMx更新中断标志 
		
		LED1=!LED1;
		if(VirtualUart.send_mode) //发送模式:非阻塞
		{
			if(tim_send_byte(send_remain_byte)==0)//=0说明发送结束 
			{
				if(VirtualUart.send_flag==0)//发送处在结束状态				
					TIM4->CR1 &= ~TIM_CR1_CEN;//关闭定时器
					TIM4->CNT=0;							//清除定时器计数的数值
					
			}
		}
//		else //
//		{
//			if(tim_send_byte(NULL)==0) 
//			{
//				TIM4->CR1 &= ~TIM_CR1_CEN;//关闭定时器
//				TIM4->CNT=0;							//清除定时器计数值
//			}
//		}		
			

	}
}

3 非阻塞式通讯-发送操作

这也不难作,来来回回就是有点绕

我 参考如下前人做的来进行的!

https://blog.youkuaiyun.com/yunjie167/article/details/79808464

保护版权,不再赘述!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiaoxilang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值