利用STM32 中断进行串口数据读写,由于引入中断机制,串口的读是放在中断回调函数中,由于中断的高速性,很容易引起指定的缓存区满,因此增加串口读缓冲队列,是保证数据高效可靠的保证。
STM32中,没有高级操作系统中的线程调度这一概念,也就无锁的概念,但是中断的优先级高,会不停的打断主程序的执行,当主程序重回中断向量位置时,由于中断对一些数据状态的改变,主程序很容易读到脏数据。因为缓冲队列是作为公共缓冲区的中转场合,势必会造成中断部分与主程序部分的争用问题,为了解决这种竞态争用队列的问题,采用传统的递归扫描队列中的环形数组状态的方法,就不可行了,递归的过程中很容易读到脏数据了。
分析中发现,由于缓冲区较大,读、写部分,是对缓冲区中的不同部分来分开处理的,因此可以把公共竞态的部分,缩小,缩小到状态位的处理,这样争用就少了,但是单独靠状态位,无方向性,因此引入了计数器,只需要比较读、写状态的计数差值,就知道了当前读、写的区间段,为了保证环形数组构造的队列的可循环性,还需要引入游标机制,来确定读、写部分的当前位,游标读、写独立游标,二者唯一需要交互的就是计数器了,利用此方法解决竞态问题。这种机制由于不是高级操作系统的锁那种在CPU上强制做排他处理,因此队列部分无法满足多个输入中断同时进入,多个中断之间的计数会引起竞态。
ReceiveBufferData receiveBufferQueue[20];//½ÓÊÕ¶ÓÁÐ
int writeBufferQueueCursor=0;//½ÓÊÕ¶ÓÁеÄѹÈëÓαê
int writeBufferQueueCount=0;//×ܼÆд¶ÓÁеĴÎÊý
int readBufferQueueCursor=0;//½ÓÊÕ¶ÓÁеĶÁÈ¡Óαê
int readBufferQueueCount=0;//×ܼƳɹ¦¶Á¶ÓÁеĴÎÊý
int receiveBufferQueueLen=20;//½ÓÊÕ¶ÓÁ㤶È
ReceiveBufferData emptyReceiveBufferData;//¿ÕµÄÊý¾Ý£¬ÓÃÓÚ¿ÕÅųöʹÓÃ
//ѹÈë½ÓÊÕÊý¾Ý°üµ½¶ÓÁÐ
void PushReceiveBufferData(u8 *tempReceiveBuffer,u8 receiveLen)
{
int i=0;
int tempWriteBufferQueueCursor=writeBufferQueueCursor;
ReceiveBufferData receiveItem;
writeBufferQueueCursor+=1;
if(writeBufferQueueCursor==receiveBufferQueueLen)
{
writeBufferQueueCursor=0;
}
receiveBufferQueue[writeBufferQueueCursor].ReceiveStatus=0x00;
receiveItem=receiveBufferQueue[tempWriteBufferQueueCursor];
receiveItem.ReceiveLength=receiveLen;
for(i=0;i<receiveLen;i++)
{
*(receiveItem.ReceiveBuffer+i)=*(tempReceiveBuffer+i);
}
receiveItem.ReceiveStatus=0x01;
receiveBufferQueue[tempWriteBufferQueueCursor]=receiveItem;
writeBufferQueueCount+=1;
}
//µ¯³öÐèÒª´¦ÀíµÄ½ÓÊÕÊý¾Ý°ü
ReceiveBufferData PopReceiveBufferData()
{
int tempReadBufferQueueCursor=readBufferQueueCursor;
ReceiveBufferData receiveItem;
if(readBufferQueueCount>=writeBufferQueueCount)
{
emptyReceiveBufferData.ReceiveStatus=0x00;
return emptyReceiveBufferData;
}
readBufferQueueCursor+=1;
if(readBufferQueueCursor==receiveBufferQueueLen)
{
readBufferQueueCursor=0;
}
receiveItem=receiveBufferQueue[tempReadBufferQueueCursor];
if(receiveItem.ReceiveStatus==0x01)
{
receiveItem.ReceiveStatus=0x02;
}
receiveBufferQueue[tempReadBufferQueueCursor]=receiveItem;
readBufferQueueCount+=1;
return receiveItem;
}