最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

DSP

运维笔记admin21浏览0评论

DSP

DSP

在文章DSP_控制程序框架与优化-CSDN博客这篇文章中,我提到了用“高频小队列”的方式去处理与上位机的通信程序,最小的队列,就是一个节点只存储一个字节。用串口和上位机通信的方式是非常普遍的,本文讲描述一种串口通信的“高频小队列”框架。本框架其实核心的思想就是将串口的接收中断配置成1个字节就触发一次,中断处理程序只做一件事,就是把接收到的1个字节push到接收队列当中,然后在主程序 while(1)中去处理接收到的数据,对数据进行帧解析,为了让这个框架更普适,我们通过帧头和帧尾来截取一帧完整的数据,这样就能普适不定长的通信协议。 但帧解析的方式也很精细,我们是以10kHz的频率来处理,一次只处理一个字节,而不是直接一次把队列里面所有的数据都处理了。 同样的,我们要把数据通过串口发送给上位机,首先也是把需要发送的数据先一个字节一个字节的push到发送队列中,然后同样以10kHz的频率,一次只发送一帧出去,而不是一次性发完。

无论是接收数据、帧解析还是发送数据都是1字节1字节的处理,这样做的好处是,能够减少主程序对CPU时间片的需求。 进一步避免由于中断程序占用CPU时间片过长的问题。 如果中断占用CPU时间过长, 而主程序又是一次性处理很多数据(包括帧解析和发送),那么很有可能出现CPU一直被中断占用,而主程序又无法正常的执行的情况,最终呈现出来就是你上位机给DSP发信息,DSP直接无响应, DSP也无法发信息给上位机。

鲁棒的程序写法是,中断程序对CPU占用要尽量的减少,甚至一些不那么重要的但需要实时运行的程序比如ADC数据采集也可以放在while(1)之下,而不要全部放在中断程序中。  比如你ADC数据采集花了特别多的时间,导致中断处理程序的运行时间基本上快达到中断触发周期了,那留给其他中断和主程序的CPU时间片已经不多了,这就会导致程序异常,特别是主程序如果帧解析不是1个字节1个字节的解析的,发送数据也不是1个字节一个字节发送的。 这时候主程序的运行肯定就不正常了。 

总得来说,中断程序一定是尽量的用时短而美,主程序while(1)里面的数据处理程序也是尽量的用时短而美,而不是一次性做很复杂的操作。

串口配置和单字节队列处理 

/** scib.h**/#ifndef USERPROGRAM_PC_SCIB_H_
#define USERPROGRAM_PC_SCIB_H_
#include <main.h>
//  Select the Baud rate of SCI
//  #define _BAUD_9600_
//  #define _BAUD_38400_
#define _BAUD_115200_
//#define _BAUD_256000_
//#define _BAUD_187500_
// #define _BAUD_460800_
//#define _BAUD_921600_void para_init(void);
void configScib(void);
void configScibGpio(void);
void configScibRegister(void);void ScibInterruptInit(void);#define MAX_RX_FRAME_SIZE 100extern Uint16 u_data_frame_array[MAX_RX_FRAME_SIZE];
extern Uint16 u_data_frame_length;
extern Uint16 is_data_frame_available;interrupt void getScib(void);
void sendScib(void);
void get_data_frame(void);#endif /* USERPROGRAM_PC_SCIB_H_ */

 

/** scib.c**/
#include <scib.h>// The communication port for display and control debugging is generally serial port
// SCI, Serial Communications Interfacevoid configScib(void)
{para_init();configScibGpio();configScibRegister();ScibInterruptInit();
}// Configure the multiplexing function of GPIO pin used by Scic
void configScibGpio(void)
{EALLOW;GpioCtrlRegs.GPAPUD.bit.GPIO18 = 0;    // Enable pull-up for GPIO18 (SCITXDB)GpioCtrlRegs.GPAPUD.bit.GPIO19 = 0;     // Enable pull-up for GPIO19 (SCIRXDB)GpioCtrlRegs.GPAQSEL2.bit.GPIO19 = 3;  // Asynch input GPIO19 (SCIRXDB)GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 2;   // Configure GPIO18 for SCITXDB operationGpioCtrlRegs.GPAMUX2.bit.GPIO19 = 2;   // Configure GPIO19 for SCIRXDB operationEDIS;
}// Configure relevant registers of Scic
void configScibRegister(void)
{/*---------------------------------------------SCICCR-------------------------------------------------------------*/// SCI number of stop bitsScibRegs.SCICCR.bit.STOPBITS        = 0;    // 0: One stop bit                                          ▲// 1: Two stop bit// SCI parity odd/even selectionScibRegs.SCICCR.bit.PARITY          = 0;    // 0: Odd  parity// 1: Even parity// SCI parity enableScibRegs.SCICCR.bit.PARITYENA       = 0;    // 0: Parity disabled                                       ▲// 1: Parity is enabled// Loop Back test mode enableScibRegs.SCICCR.bit.LOOPBKENA       = 0;    // 0: Loop Back test mode disabled// 1: Loop Back test mode enabled// SCI multiprocessor mode control bitScibRegs.SCICCR.bit.ADDRIDLE_MODE   = 0;    // 0: Idle-line mode protocol selected// 1: Address-bit mode protocol selected// Character-length control bits 2-0ScibRegs.SCICCR.bit.SCICHAR         = 7;    // 0: SCICHAR_LENGTH_1                                      ▲// 1: SCICHAR_LENGTH_2// 7: SCICHAR_LENGTH_8/*---------------------------------------------SCICTL1--------------------------------------------------------------*/// SCI receive error interrupt enableScibRegs.SCICTL1.bit.RXERRINTENA    = 0;    // 0: Receive error interrupt disabled// 1: Receive error interrupt enabled// SCI software reset (active low)ScibRegs.SCICTL1.bit.SWRESET        = 0;    // 0: Writing a 0 to this bit initializes the SCI state machines// and operating flags (registers SCICTL2 and SCIRXST) to the reset condition.// 1: After a system reset, re-enable the SCI by writing a 1 to this bit.// SCI transmitter wake-up method selectScibRegs.SCICTL1.bit.TXWAKE         = 0;    // 0: Transmit feature is not selected. In idle-line mode: write// a 1 to TXWAKE, then write data to register SCITXBUF to generate// an idle period of 11 data bits / In address-bit mode: write a 1 to// TXWAKE, then write data to SCITXBUF to set the address bit for// that frame to 1// SCI sleep.ScibRegs.SCICTL1.bit.SLEEP          = 0;    // 0: Sleep mode disabled// 1: Sleep mode enabled// SCI Transmitter enableScibRegs.SCICTL1.bit.TXENA          = 1;    // 0: Transmitter disabled                                  ▲// 1: Transmitter enabled// SCI receiver enableScibRegs.SCICTL1.bit.RXENA          = 1;    // 0: Prevent received characters from transfer into the    ▲// SCIRXEMU and SCIRXBUF receiver buffers// 1: Send received characters to SCIRXEMU and SCIRXBUF/*---------------------------------------------SCICTL2------------------------------------------------------------*/ScibRegs.SCICTL2.bit.TXINTENA       = 1;    // SCITXBUF-register interrupt enable                       ▲ScibRegs.SCICTL2.bit.RXBKINTENA     = 1;    // Receiver-buffer/break interrupt enable                   ▲/*---------------------------------------------SCIHBAUD & SCILBAUD-------------------------------------------------*/// BRR = (SCIHBAUD << 8) + (SCILBAUD) = LSPCLK / (SCI Asynchronous Baud * 8) - 1#ifdef _BAUD_9600_ScibRegs.SCIHBAUD               = 0x0001;   // 9600 baud @ LSPCLK = 150/4 = 37.5MHz.                    ▲ScibRegs.SCILBAUD               = 0x00E7;   // 487.28d →  487d#endif#ifdef _BAUD_38400_ScibRegs.SCIHBAUD               = 0x0000;   // 38400 baud @ LSPCLK = 150/4 = 37.5MHz.                   ▲ScibRegs.SCILBAUD               = 0x0079;   // 121.07d →  121d#endif#ifdef _BAUD_115200_ScibRegs.SCIHBAUD               = 0x0000;   // 115200 baud @ LSPCLK = 150/4 = 37.5MHz.                  ▲ScibRegs.SCILBAUD               = 0x0028;   // 39.69d →  40d#endif#ifdef _BAUD_187500_ScibRegs.SCIHBAUD               = 0x0000;   // 115200 baud @ LSPCLK = 150/4 = 37.5MHz.                  ▲ScibRegs.SCILBAUD               = 0x0018;   // 39.69d →  40d#endif#ifdef _BAUD_256000_ScibRegs.SCIHBAUD               = 0x0000;   // 460800 baud @ LSPCLK = 150/4 = 37.5MHz.                  ▲ScibRegs.SCILBAUD               = 0x0011;   // 39.69d →  40d#endif#ifdef _BAUD_460800_ScibRegs.SCIHBAUD               = 0x0000;   // 460800 baud @ LSPCLK = 150/4 = 37.5MHz.                  ▲ScibRegs.SCILBAUD               = 0x0009;   // 39.69d →  40d#endif#ifdef _BAUD_921600_ScibRegs.SCIHBAUD               = 0x0000;   // 460800 baud @ LSPCLK = 150/4 = 37.5MHz.                  ▲ScibRegs.SCILBAUD               = 0x0004;   // 39.69d →  40d#endif// Relinquish SCI from Reset 【迷惑行为】ScibRegs.SCICTL1.all                = 0x0023;/*---------------------------------------------SCIFFTX & SCIFFRX-------------------------------------  ------------*/ScibRegs.SCIFFTX.bit.SCIRST         = 1;    // SCI ResetScibRegs.SCIFFTX.bit.SCIFFENA       = 1;    // SCI FIFO enableScibRegs.SCIFFTX.bit.TXFIFOXRESET   = 1;    // Transmit FIFO resetScibRegs.SCIFFTX.bit.TXFFST         = 0;    // FIFO status  0:      Transmit FIFO is empty//              1:      Transmit FIFO has 1 words//              10H:    Transmit FIFO has 16 wordsScibRegs.SCIFFTX.bit.TXFFINTCLR     = 0;    // Transmit FIFO clearScibRegs.SCIFFTX.bit.TXFFIENA       = 0;    // Transmit FIFO interrrupt enableScibRegs.SCIFFTX.bit.TXFFIL         = 9;   // TXFFIL4-0 Transmit FIFO interrupt level bits.ScibRegs.SCIFFRX.bit.RXFFOVRCLR     = 1;    // RXFFOVF(Receive FIFO overflow) clearScibRegs.SCIFFRX.bit.RXFIFORESET    = 1;    // Receive FIFO resetScibRegs.SCIFFRX.bit.RXFFST         = 6;    // FIFO status  0:      Receive FIFO is empty//              1:      Receive FIFO has 1 words//              10H:    Receive FIFO has 16 wordsScibRegs.SCIFFRX.bit.RXFFINTCLR     = 1;    // Receive FIFO interrupt clearScibRegs.SCIFFRX.bit.RXFFIENA       = 1;    // Receive FIFO interrupt enable// ScibRegs.SCIFFRX.bit.RXFFIL         = 6;   // Receive FIFO interrupt level bitsScibRegs.SCIFFRX.bit.RXFFIL         = 1;   // Receive FIFO interrupt level bits
}void ScibInterruptInit(void){// SCIBRXINT INT9.3// SCIBTXINT INT9.4// SCICRXINT InitialEALLOW;PieVectTable.SCIRXINTB = &getScib;          // Specify the interrupt service routineEDIS;IER |= M_INT9;                              // Enable CPU Level interruptPieCtrlRegs.PIEIER9.bit.INTx3=1;            // Enable PIE Level interrupt// SCICTXINT Initial// TODO
}// get one byte and push
interrupt void getScib(void)
{Uint16 data = ScibRegs.SCIRXBUF.all;enqueue(&scib_rx_queue, data);ScibRegs.SCIFFRX.bit.RXFIFORESET    = 0;ScibRegs.SCIFFRX.bit.RXFIFORESET    = 1;ScibRegs.SCIFFRX.bit.RXFFINTCLR     = 1;PieCtrlRegs.PIEACK.all  = PIEACK_GROUP9;
}// pop and send one byte
void sendScib(void)
{Uint16 data = 0;int ret = dequeue(&scib_tx_queue, &data);if(ret == 1){ScibRegs.SCITXBUF = data;while (ScibRegs.SCICTL2.bit.TXRDY == 0);}
}Uint16 last_data = 0;
Uint16 is_framehead_identified = 0;
Uint16 u_data_frame_effective_cnt = 0;
Uint16 u_data_frame_array[MAX_RX_FRAME_SIZE];
Uint16 is_data_frame_available = 0;
Uint16 u_data_frame_length = 0;void para_init(void)
{int i = 0;queue_init(&scib_rx_queue);queue_init(&scib_tx_queue);for(i = 0; i < MAX_RX_FRAME_SIZE; i++){u_data_frame_array[i] = 0;}
}// Indefinite length data frame acquisition
void get_data_frame(void)
{Uint16 data = 0;int ret = dequeue(&scib_rx_queue, &data);// The scib_rx_queue is not emptyif(ret == 1){// Frame head recognitionif(last_data==0x55 && data==0xAA){is_framehead_identified = 1;u_data_frame_array[0] = 0x55;u_data_frame_array[1] = 0xAA;u_data_frame_effective_cnt = 2;// Frame tail recognition}else if(is_framehead_identified==1 && last_data==0x66 && data==0x88){u_data_frame_array[u_data_frame_effective_cnt] = data;u_data_frame_length = u_data_frame_effective_cnt + 1;is_data_frame_available = 1;// save Frame data}else if(is_framehead_identified==1 && u_data_frame_effective_cnt < (MAX_RX_FRAME_SIZE-1)){u_data_frame_array[u_data_frame_effective_cnt] = data;u_data_frame_effective_cnt++;// frame length error}else if(is_framehead_identified==1 && u_data_frame_effective_cnt >= (MAX_RX_FRAME_SIZE-1)){last_data = 0;u_data_frame_effective_cnt = 0;is_framehead_identified = 0;}last_data = data;// The scib_rx_queue is empty}else{return;}
}/*
void sendScib(void)
{if(u_fr_tx_flag==1 && u_fr_tx_index < 16){ScibRegs.SCITXBUF   = u_fr_tx_buf[u_fr_tx_index] & 0x00FF;u_fr_tx_index++;while (ScibRegs.SCICTL2.bit.TXRDY == 0);}else{u_fr_tx_flag = 0;u_fr_tx_index = 0;}}
*/

 

主程序和主中断

    while(1){// 10kHzif(iFreq10000Hz == 1){get_adc();  // ADC如果耗时过多,可以放在主程序里,系统也能实现接近10kHz的性能// ADC如果耗时不多,放在主程序里,系统肯定是实现10kHz的性能// Pop and handle 【one byte】get_data_frame();// Execute PC Commandif(is_data_frame_available==1){fr_recv_decode();is_data_frame_available = 0;}// Pop and send 【one byte】sendScib();//runtime_stop(&runtime1);iFreq10000Hz = 0;}}
// 用时最多的主中断(可能其他中断用0.几~几us,主中断用 < 50us的运行时间)
// 10kHz的话,相当于留50%的时间片给其他的中断和主程序
// 即使主程序运行一回要超过50us(但超过的不多哈),那整个系统基本上也是10kHz实时运行的。
interrupt void SystemMain(void)
{// do your main task// 用时短 而 美iFreq10000Hz = 1;PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;}

 

发布评论

评论列表(0)

  1. 暂无评论