请教马老师:基于队列的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);
}
} 查询方式发送和中断方式发送 两者只能选择其中一种方式。
要么你使用查询方式发送,要么你使用中断方式发送。
问题:
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); //禁止空中断
} 回复【1楼】ba_wang_mao
-----------------------------------------------------------------------
回复:
为什么空中断发送不能这样写“void UART_send(unsigned char *buf,unsigned char len)//发送指定长度的数据 ”
在这函数下,也是:(1)将等发送数据装载到发送队列中
(2)UCSRB|=(1<<UDRIE);//数据空中断允许 被无视了。。。。 建议您购买我的教材,从基础开始,逐步深入。 回复【4楼】machao
-----------------------------------------------------------------------
老师你好,你的书我已经看完了一篇,正在消化ing,关于你的UART底层与中层的程序几乎能了解,但上的我转载的程序不知怎么样只能发送数组的第一个,很疑惑。。。能点一下学生吗??? 为什么空中断发送不能这样写“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);)。
则是正确的。 可能的问题如下:
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); 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);
} 经过软件的调试,也发现主要的问题应该出现在发送空中断里,但不知道为什么呢???
当要发送数组中的第二个数时,UCSRA寄存器中的UDRE自动请为零。。。
SOS,痛苦中,挣扎。。。。。 你还是用简单的数组进行调试,或者更恰当的说,先学习基本的。
建立一个5个字节的固定内容的数组,然后发送,如果成功,再使用队列什么的。如果不成功,找原因。 本帖最后由 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]