0520kuang 发表于 2011-2-18 17:04:04

请教马老师:基于队列的Mega8 UART通信驱动程序(转载的)

本想发送一组数据,可是只能发送数组中的第一个数,
如:定义一组数据unsigned char Tab[]={0x01,0x10,0x00,0x01,0x00,0x02,0x04,0x00,0x0A,0x01,0x02,0xE2,0x37};
    可是只能发送第一个。。。。麻烦帮忙看看程序哪里有问题????

#include<iom16v.h>
#include<macros.h>

#define UART_BUF_SIZE 16      //UART数据缓冲区长度定义

unsigned char SendBuffer;//发送缓冲区
unsigned char RecvBuffer;//接收缓冲区
unsigned char Tab[]={0x01,0x10,0x00,0x01,0x00,0x02,0x04,0x00,0x0A,0x01,0x02,0xE2,0x37};
#pragma data:data
/***************************************************************/
//队列数据结构
typedef struct Queues
{
       unsigned char in_index;//入队地址
   unsigned char out_index;//出队地址
   unsigned char buf_size; //缓冲区长度
   unsigned char *pBuffer;//缓冲
   volatile unsigned char data_count; //队列内数据个数
}HQueue,*PHQueue;

HQueue H_SendQueue;//发送队列句柄
HQueue H_RecvQueue;//接收队列句柄

void QueueInput(PHQueue Q,unsigned char dat)//向队列写入一字节
{
       if(Q->data_count<Q->buf_size )
       {
             Q->pBuffer=dat;//写入数据
               Q->in_index=(Q->in_index+1)%(Q->buf_size);//调整入口地址
               Q->data_count++; //调整数据个数
       }       
}

unsigned char QueueOutput(PHQueue Q)//从队列读出一字节
{
       unsigned char cData;
       if(Q->data_count > 0 )
       {
             cData=Q->pBuffer;
             Q->out_index=(Q->out_index+1)%(Q->buf_size);//调整入口地址
             Q->data_count--;//调整数据个数
       }
       return cData;
}

unsigned char QueueGetDataCount(PHQueue Q)//获得队列中数据个数
{
       return Q->data_count;
}

void QueueClear(PHQueue Q) //清空队列
{
       Q->in_index=0;
       Q->out_index=0;
       Q->data_count=0;
}

void QueueCreate(PHQueue Q,unsigned char *buffer,unsigned char buf_size)//初始化一队列
{
       Q->pBuffer=buffer;
       Q->buf_size=buf_size;
       QueueClear(Q);
}
/******************************************************************/
/**************************************************************/
#pragma interrupt_handler uart0_rx_isr:12//接收中断
void uart0_rx_isr(void)
{
       unsigned char c;
       c=UDR;
       QueueInput(&H_RecvQueue,c);
}

#pragma interrupt_handler uart0_udre_isr:13 //发送寄存器空中断
void uart0_udre_isr(void)
{
       if(QueueGetDataCount(&H_SendQueue)>0)
       {             
             UDR=QueueOutput(&H_SendQueue);
       }
       else
             UCSRB&=~(1<<UDRIE);
}
/*********************************************************************/
void UART_Init(void)
{
       UCSRA=0x00;
       UCSRB=(1<<RXCIE)|(1<<RXEN)|(1<<TXEN);
       UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);//8位 无校验 1停止位
       UBRR=25; //9600 4MHZ
       QueueCreate(&H_SendQueue,SendBuffer,UART_BUF_SIZE);
       QueueCreate(&H_RecvQueue,RecvBuffer,UART_BUF_SIZE);
       
}

unsigned char UART_recv(unsigned char *buf)//读接收缓冲内的数据
{
       unsigned char Len;
       for(Len=0;Len<UART_BUF_SIZE;Len++)
       {
             if(QueueGetDataCount(&H_RecvQueue)==0)          
                       break;
               else
                     buf=QueueOutput(&H_RecvQueue);
       }
       return Len; //返回实际接收的长度
}

void UART_send(unsigned char *buf,unsigned char len)//发送指定长度的数据
{
       unsigned char i;
       CLI();
       QueueClear(&H_SendQueue);
       for(i=0;i<len;i++)
       {
             QueueInput(&H_SendQueue,buf);               
       }
//       UDR=QueueOutput(&H_SendQueue);
       UCSRB|=(1<<UDRIE);//数据空中断允许
       SEI();
}

void main(void)
{   
       UART_Init();
       SEI();
       while(1)
       {
                   UART_send(Tab,13);
       }

}

ba_wang_mao 发表于 2011-2-18 17:29:41

查询方式发送和中断方式发送 两者只能选择其中一种方式。

   要么你使用查询方式发送,要么你使用中断方式发送。


问题:
   1、寄存器没有配置中断方式发送,是否允许接收,是否允许中断接收等。

   2、如果没有配置中断方式发送,而在程序中出现中断方式发送的中断报务程序,可有能出错。

   3、空中断发送不是如你的“void UART_send(unsigned char *buf,unsigned char len)//发送指定长度的数据 ”
      那样书写,正确的格式如下:

            (1)、首先允许中断方式发送
            (2)、将等发送数据装载到发送队列中
            (3)、书写void UART_send(void)
                   {
                        UCSRB|=(1<<UDRIE);//数据空中断允许
                   }
            (4)、编写空中断服务程序

                   #pragma interrupt_handler uart0_udre_isr:13 //发送寄存器空中断
                   void uart0_udre_isr(void)
                   {
                     if(QueueGetDataCount(&H_SendQueue)>0)
                     {      
                            UDR=QueueOutput(&H_SendQueue);
                        }
                     else
                        UCSRB&=~(1<<UDRIE);   //禁止空中断
                     }

0520kuang 发表于 2011-2-18 18:49:18

回复【1楼】ba_wang_mao
-----------------------------------------------------------------------
回复:
为什么空中断发送不能这样写“void UART_send(unsigned char *buf,unsigned char len)//发送指定长度的数据 ”

在这函数下,也是:(1)将等发送数据装载到发送队列中
                  (2)UCSRB|=(1<<UDRIE);//数据空中断允许

0520kuang 发表于 2011-2-19 11:18:13

被无视了。。。。

machao 发表于 2011-2-21 15:59:56

建议您购买我的教材,从基础开始,逐步深入。

0520kuang 发表于 2011-2-21 23:14:37

回复【4楼】machao
-----------------------------------------------------------------------

老师你好,你的书我已经看完了一篇,正在消化ing,关于你的UART底层与中层的程序几乎能了解,但上的我转载的程序不知怎么样只能发送数组的第一个,很疑惑。。。能点一下学生吗???

ba_wang_mao 发表于 2011-2-22 10:47:48

为什么空中断发送不能这样写“void UART_send(unsigned char *buf,unsigned char len)//发送指定长度的数据 ”

在这函数下,也是:(1)将等发送数据装载到发送队列中
                  (2)UCSRB|=(1<<UDRIE);//数据空中断允许   
//------------------------------------------------------------------------------------

   如果你想表达如下意思,则是正确的:

      1、unsigned char *buf= 待发送报文缓冲区
      2、unsigned char len = 待发送报文长度
      3、然后通过入队的方式,追加到发送队列
      4、最后允许数据空中断
      5、在数据空中断服务程序中,根据发送队列是否为空,判断是继续发送数据(UDR=QueueOutput(&H_SendQueue); ),
         还是停止数据空中(UCSRB&=~1<<UDRIE);)。




   则是正确的。

ba_wang_mao 发表于 2011-2-22 10:54:31

可能的问题如下:

      1、在数据空中断服务程序中

         if(QueueGetDataCount(&H_SendQueue)>0)
          {      
             UDR=QueueOutput(&H_SendQueue);
          }
      


      为什么不写成如下形式:

       (1)、编写队列空函数BOOL Queue_Empty(void)    ------>这是队列的基本函数
       (2)、编写队列满函数BOOL Queue_Full(void)   ------>这是队列的基本函数
       (3)、编写入队函数    BOOL Queue_In(INT8U ch)   ------>这是队列的基本函数
       (4)、编写出队函数    BOOL QUEUE_Out(INT8U *ch)------>这是队列的基本函数


      INT8U ch;

         if (!Queue_Empty())
         {
                  Queue_Out(&ch);
                  UDR = ch;
         }
         else
         UCSRB&=~(1<<UDRIE);

ba_wang_mao 发表于 2011-2-22 11:01:15

1、下面是单个队列的标准格式
2、如果你的程序中需要多个队列,可以在这个标准格式下,改造符合你的需求。
   例如:
      QUEUE_Init(void)
   改造成
      QUEUE_Init(队列名)


      BOOL QUEUE_In(INT8U ch)
   改造成
      BOOL QUEUE_In(队列名,INT8U ch)




#define QUEUE_MAX_LENGTH (255)

struct EEPROM_QUEUE
{
        INT8U element;
        INT8U rear;
        INT8U front;
};

struct EEPROM_QUEUE QUEUE;

void QUEUE_Init(void)
{
        QUEUE.rear = 0;
        QUEUE.front = 0;
}


BOOL QUEUE_EMPTY(void)
{
        if (QUEUE.rear == QUEUE.front)
                return (TRUE);
        return (FALSE);
}


BOOL QUEUE_FULL(void)
{
        if ((QUEUE.rear+1) % QUEUE_MAX_LENGTH == QUEUE.front)
                return (TRUE);
        return (FALSE);
}


BOOL QUEUE_In(INT8U ch)
{
        if (!QUEUE_FULL())
        {
                QUEUE.rear = (QUEUE.rear + 1) % QUEUE_MAX_LENGTH;
                QUEUE.element = ch;
                return (TRUE);
        }
        return (FALSE);
}


BOOL QUEUE_Out(INT8U *ch)
{
        if (!QUEUE_EMPTY())
        {
                QUEUE.front = (QUEUE.front + 1) % QUEUE_MAX_LENGTH;
                *ch = QUEUE.element;
                return (TRUE);
        }
        return (FALSE);
}

0520kuang 发表于 2011-2-23 18:51:10

经过软件的调试,也发现主要的问题应该出现在发送空中断里,但不知道为什么呢???

当要发送数组中的第二个数时,UCSRA寄存器中的UDRE自动请为零。。。

SOS,痛苦中,挣扎。。。。。

machao 发表于 2011-2-23 21:39:57

你还是用简单的数组进行调试,或者更恰当的说,先学习基本的。

建立一个5个字节的固定内容的数组,然后发送,如果成功,再使用队列什么的。如果不成功,找原因。

twd3621576 发表于 2012-12-14 14:32:18

本帖最后由 twd3621576 于 2012-12-14 14:38 编辑

void UART_send(unsigned char *buf,unsigned char len)//发送指定长度的数据
{
         unsigned char i;
         CLI();
         QueueClear(&H_SendQueue);
         for(i=0;i<len;i++)
         {
             QueueInput(&H_SendQueue,buf);               
         }
//         UDR=QueueOutput(&H_SendQueue);
         UCSRB|=(1<<UDRIE);//数据空中断允许
         SEI();
}

中的函数
QueueInput(&H_SendQueue,buf);               
改成
QueueInput(&H_SendQueue,buf);


UDR=QueueOutput(&H_SendQueue);
改成
for(i = 0; i<len; i++)
{
   UDR=QueueOutput(&H_SendQueue);

}
页: [1]
查看完整版本: 请教马老师:基于队列的Mega8 UART通信驱动程序(转载的)