snifer

【赛灵思FPGA】[原创]基于Xilinx FPGA的μC/OS-II的串行驱动应用

0
阅读(3114)

看天气越来越冷了,创作的激情可不能冷却。

今天主要演示一下使用串行口0用中断方式来发送和接受数据。

UART0 原理框图如下:

UART0 是一个具有帧错误检测和地址识别硬件的增强型串行口。UART0 可以工作在全双工异步方式或半双工同步方式,并且支持多处理器通信。接收数据被暂存于一个保持寄存器中,这就允许UART0 在软件尚未读取前一个数据字节的情况下开始接收第二个输入数据字节。一个接收覆盖位用于指示新的接收数据已被锁存到接收缓冲器而前一个接收数据尚未被读取。

对UART0 的控制和访问是通过相关的特殊功能寄存器即串行控制寄存器(SCON0)和串行数据缓冲器(SBUF0)来实现的。一个SBUF0 地址可以访问发送寄存器和接收寄存器。读操作将自动访问接收寄存器,而写操作自动访问发送寄存器。

程序流程

实验步骤

编写、编译、装载,连续运行程序,在PC上用超级终端来显示和发送数据。本程序会通过串口发送进入系统的欢迎信息,并在超级终端运行简单的shell-v命令,reboot命令以及命令错误的提示信息,其中v命令显示操作系统版本信息,reboot命令重新启动系统。

实验程序

#include "includes.h"

 

/*  Constants */

#define SYSCLK   25000000

#define BAUDRATE 9600               //波特率默认为9600

#define RX_LENGTH    16

sbit P35=P3^5;

 

/*

*********************************************************************************************************

*                                              VARIABLES

*********************************************************************************************************

*/

 

OS_STK TaskStkStart[MaxStkSize];

OS_STK TaskStkA[MaxStkSize];

OS_STK TaskStkB[MaxStkSize];

OS_STK TaskStkC[MaxStkSize];

OS_STK TaskStkD[MaxStkSize];

OS_STK TaskStkE[MaxStkSize];

 

TASK_USER_DATA xdata TaskUserData[20];

 

/*

*********************************************************************************************************

*                                         FUNCTION PROTOTYPES

*********************************************************************************************************

*/

void TaskStart(void*) reentrant;

void TaskA(void*) reentrant;

void TaskB(void*) reentrant;

void TaskC(void*) reentrant;

 

 

 

/*

*********************************************************************************************************

*                                                  MAIN

*********************************************************************************************************

*/

void main(void)

{    

      

       config();

        OSInit();

      

    strcpy(TaskUserData[0].TaskName, "TaskStart");

    //OSTaskCreate(TaskStart, (void *)0, TaskStkStart,0);

       OSTaskCreateExt(TaskStart, (void *)0, TaskStkStart,0,0,&TaskStkStart[MaxStkSize-1],

              MaxStkSize,&TaskUserData[0],OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);

    OSStart();

}

 

/*

*********************************************************************************************************

*                                               STARTUP TASK

*********************************************************************************************************

*/

void TaskStart(void *pdat) reentrant

{

      

       pdat=pdat;

      

    InitTimer0();

      

       OSStatInit();

      

    strcpy(TaskUserData[1].TaskName, "TaskA");

    strcpy(TaskUserData[2].TaskName, "TaskB");

       OSTaskCreateExt(TaskA, (void *)0, TaskStkA,1,1,&TaskStkA[MaxStkSize-1],

              MaxStkSize,&TaskUserData[1],OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);

       OSTaskCreateExt(TaskB, (void *)0, TaskStkB,2,2,&TaskStkB[MaxStkSize-1],

              MaxStkSize,&TaskUserData[2],OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);

      

       //OSTaskCreate(TaskA, (void *)0, TaskStkA,1);

    //OSTaskCreate(TaskB, (void *)0, TaskStkB,2);

    //OSTaskCreate(TaskC, (void *)0, TaskStkC,7);

    //OSTaskCreate(TaskD, (void *)0, TaskStkD,5);

      

   for(;;)

       {

              //OSTaskStkChk(0, &TaskUserData[0].dat);

              //OSCtxSwCtr = 0;

              OSTimeDlyHMSM(0, 0, 1, 0);

    }   

}

/****************************************************************************************

*   TaskA():系统运行指示灯

****************************************************************************************/

void TaskA( void *pData ) reentrant

{

    pData = pData;

      

    for(;;)

    {

              P35=~P35;

              //OSTaskStkChk(1, &TaskUserData[1].dat);

        OSTimeDlyHMSM(0, 0, 0, 100);

       }

}

 

 

/****************************************************************************************

*   TaskB():接受串口命令

****************************************************************************************/

void TaskB(void *pdat) reentrant

{

       extern bit       RX_Ready;                          // '1' means RX string received

       extern char idata RX_Buf[RX_LENGTH];          // receive string storage buffer

      

       pdat=pdat;

      

       UART0_Init();

      

       Welcome();

      

       while (1)

       {                         // echo messages

              if (RX_Ready == 1)          // wait for string

              {

                    

                    

                     if (RX_Buf[0] == 'r' && RX_Buf[1] == 'e'&& RX_Buf[2] == 'b' && RX_Buf[3] == 'o'

                            && RX_Buf[4] == 'o'&& RX_Buf[5] == 't'&& RX_Buf[6] == '\0')

                     {

                            CMD_Reboot();

                     }

 

                     switch (RX_Buf[0])

                     {

                    

                     case 'v' :

                            CMD_V();

                            break;

                     default:

                            CMD_Error();

                     }

             

                     cmdline: CMD_Line();

                     RX_Ready = 0;                    // free the receiver

              }

              //OSTaskStkChk(2, &TaskUserData[2].dat);

              OSTimeDlyHMSM(0, 0, 0, 500);   

       }

}/*显示欢迎信息*/

void Welcome(void)

{

       EA  = 0;

       TI0  = 1;

       printf("\n/********************uC/OS-II, The Real-Time Kernel********************/\n");

       printf("\n                  Welcome to the uC/OS-II command mode!                 \n");

       printf("\n/**********************************************************************/\n\n");

       printf(">");    

       TI0 = 0;

       EA        = 1;

}

 

/****************************************************************************************

*   void CMD_V():V命令功能函数,显示系统版本号

*   参数:无

****************************************************************************************/

void CMD_V(void)

{

       EA  = 0;

       TI0  = 1;

       printf( "uC/OS-II V%1d.%02d", OSVersion() / 100, OSVersion() % 100);

       TI0 = 0;

       EA        = 1;       

}

/****************************************************************************************

*   void CMD_Reboot():reboot命令功能函数,重新启动

*   参数:无

****************************************************************************************/

void CMD_Reboot(void)

{

       RSTSRC |= 0x02;

}

/****************************************************************************************

*   void CMD_ERROR():命令不匹配时的功能函数

*   参数:无

****************************************************************************************/

void CMD_Error(void)

{

       EA  = 0;

       TI0  = 1;

      

       printf("Bad command.\nPlease input help or ? get for help.\n");

      

       TI0 = 0;

       EA        = 1;

}

void CMD_Line(void)

{

       EA  = 0;

       TI0  = 1;

       printf("\n\n>");

       TI0 = 0;

       EA        = 1;

}

//串口0中断服务程序

void UART0_ISR(void) interrupt 4

{

 

       static unsigned char RX_index = 0;  // receive buffer index

       unsigned char the_char;

      

       if (RI0 == 1)                                     // handle receive function

       {                    

              RI0 = 0;                         // clear RX complete indicator

              if (RX_Ready != 1)                          // check to see if message pending

              {            

                     the_char = SBUF0;

                     if (the_char != '\r')        // check for end of message

                     {                                               // store the character

                            RX_Buf[RX_index] = the_char;

                            // increment buffer pointer and wrap if necessary

                            if (RX_index < (RX_LENGTH - 2))

                            {

                                   RX_index++;

                            }

                            else

                            {

                                   RX_index = 0;           // if length exceeded,

                                   RX_Ready = 1;           // post message complete, and

                                   // NULL-terminate string

                                   RX_Buf[RX_index-1] = '\0';

                            }

                     }

                     else

                     {

                            RX_Buf[RX_index] = '\0';   // NULL-terminate message

                            RX_Ready = 1;              // post message ready

                            RX_index = 0;              // reset RX message index

                     }

              }

              else

              {

                     // ignore character -- previous message has not been processed

              }

       }

       else if (TI0 == 1)                              // handle transmit function

       {             

              TI0 = 0;                         // clear TX complete indicator

              the_char = *TX_ptr;              // read next character in string

              if (the_char != '\0')

              {

                     SBUF0 = the_char;             // transmit it

                     TX_ptr++;                     // get ready for next character

              }

              else

              {                         // character is NULL

                     TX_Ready = 1;                 // indicate ready for next TX

              }

       }

}

 

// 串口初始化函数

void UART0_Init()

{

       XBR0    |= 0x04;      //RX0,TX0连到2个端口引脚

       XBR2    |= 0x40;      //交叉开关允许

       P0MDOUT   |= 0x03;  //RX0,TX0口设为推挽方式,连在P0.1,P0.0上

      

       SCON0= 0x50;       //方式1: 8 位UART 可变波特

       TMOD   |= 0x20;      //定时器1为自动重装载的8 位计数器/定时器

       TMOD   |= 0x20;      //定时器1为自动重装载的8 位计数器/定时器

       TH1              = -(SYSCLK/BAUDRATE/16);

       TR1              = 1;             //启动定时器1

       CKCON       |= 0x10;//定时器1 使用系统时钟

       PCON   |= 0x80;//SMOD0=1

      

       EA         = 1;        //开中断

       ES0       = 1;

      

       TX_Ready = 1;                       // indicate TX ready for transmit

       RX_Ready = 0;                       // indicate RX string not ready

       TX_ptr   = NULL;

      

}

程序有点长,但是我都注释了的,有存在疑惑的地方可以给我留言,很多时候修改一下就能应用到其他地方了。