一种实现微观单线程,宏观上多线程的方法
1.
纵所周知的是,C语言是顺序程序设计的,那么在一些MCU中,例如STM32,Atmega168等等,在微观上程序都是单线程的,那么应该如何实现微观上的多线程呢?这个用到两个东西:一是中断,二是switch语句。听老夫为你细细道来。
2.
举个例子来说,比如我想要实现的是:MCU每2秒通过6个USART向外发送数据。一般大家首先想到的是,配置一个定时器,每2S进入一个中断函数,然后中断函数里面写入:
USART0(); //启动串口0发送
USART1(); //启动串口1发送
USART2(); //启动串口2发送
USART3(); //启动串口3发送
USART4(); //启动串口4发送
USART5(); //启动串口5发送
但是这样会存在一个问题呀。首先我可以把启动串口发送到发送数据成功分为几个部分:
1. 拉高串口读写控制端I/O,使其变为发送模式; 2. 准备要发送的数据,对数据进行组包,这一步是很耗时间的; 3. 检测串口数据是否发送完成 ; 4.在串口发送完成的时候,拉低串口读写控制端I/O,使其变为接收模式
仅仅在串口发送的就会有两个while(1),如下图所示,这无疑拖慢了CPU的运行速度,那么应该如何优化呢?
//--------------------启动发送-----------------------------//
UART0_TX; //使串口处于发送状态
i=0;
while(i<30) //一共发送30个字节
{
while(!(UCSR0A & (1<<UDRE0))); //等待 “准备数据接收”
UDR0 = *(TX_buf_MCU+(i++)); //开始发送数据
while( !( UCSR0A & (1<<TXC0)) ); //等待“发送完成”
UCSR0A |= (1<<TXC0); //发送完成后清除中断标志位
}
UART0_RC; //发送完毕,再次使串口处于接收状态
3.
先贴出代码,再详细说出
void PollingSending()
{
for (uint8_t i = 0;i < 7;i ++) //6个通道轮询发送,故循环6次
{
switch(ComState[i]) //ComState[i]表示第i个串口所处的状态
{
case 0:
if (PollingSending_Flag == 1) //当2S到,PollingSending_Flag置1
{
ComState[i] = 1; //跳到状态1
}
break;
case 1:
PollingSending_Flag = 0; //清除2S标志位
prepareData(i); //准备待发送数据包
RS485_out(i); //拉高IO口,准备发数据
ComState[i] = 2;
break;
case 2:
USARTSendStart(i); //第i个串口开始发送,此时会进入串口发送函数
ComState[i] = 3;
break;
case 3:
if (TxComplete[i] == 1) //发送完成
{
RS485_in(i); //拉低I0口,变为待接收状态
ComState[i] = 0;
}
break;
}
}
}
ISR(USART0_TXC_vect) //串口0的中断发送函数
{
if (TxLen[i] < 6) //发送6个字节
{
USART0_UDR0 = txbuf[TxLen]; //发送一个字节后会进入发送中断,进而发送另外一个字节
TxLen[chn]++;
}
else
{
TxLen[i] = 0;
TxComplete[i] = 1; //发送完毕
}
}
int main(void)
{
sysinit(); //初始化
while(1)
{
wdt_reset(); //复位看门狗
PollingSending();
}
}
此程序的优点所在是:每一个串口都有4种状态,比如
USART0:ComState[0]=0 准备发送数据
USART1:ComState[1]=3 发送完成状态
USART2:ComState[2]=2 正在发送状态
即单线程系统每次走一步,但这一步可能USART0再走,也有可能USART1拿去了。且之前也提过了,是中断发送,系统有可能处在USART1配置发送数据包的时候,这时 USART0的UCSR0A & (1<<UDRE0) == 1 了; //等待 “准备数据接收” 准备好了,那么系统就去发送USART0的数据了,关键在于,若下一时刻( UCSR0A & (1<<TXC0)) ; //等待“发送完成” 还没发送完,则系统可以不用一直在while( !( UCSR0A & (1<<TXC0)) ); //等待“发送完成”,系统可以跳出中断函数,走主程序,即继续配置USART1的数据包,这样就实现了微观上单线程,而宏观上多线程的目的。
上一篇: js执行机制 同步 异步
下一篇: php数组查找函数总结_PHP