搜索
bottom↓
回复: 11

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

[复制链接]

出0入0汤圆

发表于 2011-2-18 17:04:04 | 显示全部楼层 |阅读模式
本想发送一组数据,可是只能发送数组中的第一个数,
如:定义一组数据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[UART_BUF_SIZE];//发送缓冲区
unsigned char RecvBuffer[UART_BUF_SIZE];//接收缓冲区
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[Q->in_index]=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=(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[Len]=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);
         }

}

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 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);   //禁止空中断
                     }

出0入0汤圆

 楼主| 发表于 2011-2-18 18:49:18 | 显示全部楼层
回复【1楼】ba_wang_mao
-----------------------------------------------------------------------
回复:
为什么空中断发送不能这样写“void UART_send(unsigned char *buf,unsigned char len)//发送指定长度的数据 ”

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

出0入0汤圆

 楼主| 发表于 2011-2-19 11:18:13 | 显示全部楼层
被无视了。。。。

出0入0汤圆

发表于 2011-2-21 15:59:56 | 显示全部楼层
建议您购买我的教材,从基础开始,逐步深入。

出0入0汤圆

 楼主| 发表于 2011-2-21 23:14:37 | 显示全部楼层
回复【4楼】machao
-----------------------------------------------------------------------

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

出0入0汤圆

发表于 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);)。




   则是正确的。

出0入0汤圆

发表于 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);

出0入0汤圆

发表于 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[QUEUE_MAX_LENGTH];
        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[QUEUE.rear] = ch;
                return (TRUE);
        }
        return (FALSE);
}


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

出0入0汤圆

 楼主| 发表于 2011-2-23 18:51:10 | 显示全部楼层
经过软件的调试,也发现主要的问题应该出现在发送空中断里,但不知道为什么呢???

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

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

出0入0汤圆

发表于 2011-2-23 21:39:57 | 显示全部楼层
你还是用简单的数组进行调试,或者更恰当的说,先学习基本的。

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

出0入0汤圆

发表于 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);

}
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 18:29

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表