上传一个gcc的avr128的双串口程序,基于时间触发的调度程序
第一次上传示例,请大家有条件的测试一下,提出改进意见应用于atmega128,winavr开发环境,版本20081205,直接打开编译即可。
点击此处下载 ourdev_504909.rar(文件大小:10K) (原文件名:UsartTest.rar) 上传代码:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
typedef unsigned char uchar;
typedef unsigned intuint;
typedef unsigned long ulong;
#define fosc (11059200UL) //系统时钟
#define SCH_MAX_TASKS 2 // 调度器支持的任务个数,用户在调用调度器的时候必须设置
#define TXB8 0
#define RXB8 1
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7
#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)
// 定义调度器数据结构,每一个任务消耗 4 bytes RAM
typedef struct
{
//定义函数类型指针,const关键字意思是这是一个指向flash的指针
const void (*pTask)(void);
uchar Delay; // 任务第一次被执行前的延迟时间,如果为0则立即执行
uchar Period; // 任务的执行间隔时间,如果为0,则只执行一次
uchar RunMe; // 任务执行标志位:1 等待执行,0 不需要执行
} sTask; // sTask是结构体变量
uchar Comm0Temp;
uchar Comm1Temp;
volatile uchar usart0_recv_flag=0; //usart0接收到字符串标志
volatile uchar usart1_recv_flag=0; //usart1接收到字符串标志
volatile uchar SameFrameFlag0=3; //不等于0为同一帧,否则为下一帧
volatile uchar SameFrameFlag1=3;
sTask SCH_tasks_G;// 任务调度器数组
void Usart0CommandDeal(void);
void Usart1CommandDeal(void);
//定时器0初始化
void SCH_Init_T0(void)
{
TCNT0=0;
TCCR0 = ((1<<WGM01)|(7<<CS00)); //1024分频
OCR0=130; //108:10ms,130:12ms,162:15ms t(ms)=10*OCR0/108
TIMSK |= (1<<OCIE0); //Interrupt Timer 0 enabled
}
//增加任务
uchar SCH_Add_Task( const void (*pFunction)(void), uchar DELAY, uchar PERIOD)
{
uchar Index = 0;
while ((SCH_tasks_G.pTask != 0) && (Index < SCH_MAX_TASKS))// Have we reached the end of the list?
{
Index++;
}
if (Index == SCH_MAX_TASKS)// Task list is full
{
return SCH_MAX_TASKS;
}
SCH_tasks_G.pTask= pFunction; // If we're here, there is a space in the task array
SCH_tasks_G.Delay= DELAY;
SCH_tasks_G.Period = PERIOD;
SCH_tasks_G.RunMe= 0;
return Index; // return position of task (to allow later deletion)
}
SIGNAL(TIMER0_COMP_vect)//(SIG_OVERFLOW0)
{
uchar Index;
for ( Index = 0;Index < SCH_MAX_TASKS;Index++ )
{
if (SCH_tasks_G.Delay == 0)
{
//给可以被调度的任务设置标志位
//说明:任务运行标志位不具有存储功能,也就是说,如果在规定的
// 间隔内没有被运行,则机会丧失
SCH_tasks_G.RunMe = 1;// Inc. the 'Run Me' flag
SCH_tasks_G.Delay = SCH_tasks_G.Period;//将任务需要的延时装入
}
else
{
SCH_tasks_G.Delay --;//延时-1
}
}
}
//串口0初始化
void usart0_init( uint baud )
{
uint UBRR;
PORTE|=0x03;
DDRE|=0x03;
UBRR=(fosc/16/baud)-1;
/* 设置波特率*/
UBRR0H = (UBRR>>8);
UBRR0L = UBRR;
UCSR0B = (1<<RXCIE0)|(1<<TXCIE0)|(1<<RXEN0)|(1<<TXEN0); /* 接收器与发送器使能*/
UCSR0C = (1<<UCSZ01)|(1<<UCSZ00); /* 设置帧格式: 8 个数据位, 1 个停止位 */
}
// 定义 USART0 接收变量**********************************************
#define RX_BUFFER_SIZE0 80
uchar rx_buffer0; //接收缓存
// USART0 写、读指示及缓存中数据的字节数
volatile uchar rx_wr_index0=0;
volatile uchar rx_rd_index0=0;
volatile uchar rx_counter0=0;
// USART0 接收中断*****************************************************
SIGNAL(SIG_UART0_RECV)
{
uchar Temp;
usart0_recv_flag=1;
SameFrameFlag0=3;
//判断有无错误,(FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN)=0X1C
if((UCSR0A&(FRAMING_ERROR|PARITY_ERROR|DATA_OVERRUN))==0)
{
rx_buffer0=UDR0; //接收数据至缓存区
if(++rx_wr_index0==RX_BUFFER_SIZE0)
rx_wr_index0=0; //缓存区满后写指示指向缓存区头
if(++rx_counter0==RX_BUFFER_SIZE0) //缓存区数据满后
rx_counter0=0; //清零字节记数值
}
else
Temp=UDR0;
}
// USART0 将缓存区数据读出到数组
uchar usart0_getstring(uchar *pGet)
{
uchar n=0;
while(rx_counter0)
{
*pGet++=rx_buffer0;
if(++rx_rd_index0==RX_BUFFER_SIZE0)
rx_rd_index0=0; //缓存数据读完后读指示指向缓存区头
asm volatile("cli");
--rx_counter0;
asm volatile("sei");
n++;
}
return n;
}
#define TX_BUFFER_SIZE0 80
uchar tx_buffer0; //发送缓存
// USART0 发送读写指示及缓存区字节数
volatile uchar tx_wr_index0=0;
volatile uchar tx_rd_index0=0;
volatile uchar tx_counter0=0;
// USART0 发送***************************************************************
SIGNAL(SIG_UART0_TRANS) // USART0 发送中断
{
if(tx_counter0)
{
tx_counter0-=1; //发送字节数减一
UDR0=tx_buffer0; //缓存区数据载入发送寄存器
if((++tx_rd_index0)==TX_BUFFER_SIZE0)
tx_rd_index0=0; //如果数据发送完读指示指向缓存区头
}
}
// USART0 将数据写入发送缓存区
void usart0_putchar(uchar c)
{
while(tx_counter0>=TX_BUFFER_SIZE0); //等待发送缓存中数据发送
asm volatile("cli"); //关全局中断
//如果缓存区有数据或正在发送数据
if(tx_counter0||((UCSR0A&DATA_REGISTER_EMPTY)==0))
{
tx_buffer0=c; //数据写入缓存区
if((++tx_wr_index0)==TX_BUFFER_SIZE0)tx_wr_index0=0;
tx_counter0+=1;
}
else
{
UDR0=c;
}
asm volatile("sei");
asm volatile("nop");
}
// USART0 发送ram中的字符串
void usart0_putramstring(uchar *str,uchar n)
{
while(n--)
{
usart0_putchar( *str++ );
}
}
// USART0 发送flash中的字符串
void usart0_putflashstring(char *str)
{
uchar temp=pgm_read_byte(str);
while(temp!='\0')
{
usart0_putchar( temp );
temp=pgm_read_byte(++str);
}
}
// USART0 发送n字符
void Usart0PutNChar(uchar *str,uchar n)
{
uchar i;
for(i=0;i<n;i++)
{
usart0_putchar( *str++ );
}
}
//串口1初始化
void usart1_init( uint baud )
{
uint UBRR;
PORTD|=0x0C;
DDRD|=0x0C;
UBRR=(fosc/16/baud)-1;
/* 设置波特率*/
UBRR1H = (UBRR>>8);
UBRR1L = UBRR;
UCSR1B = (1<<RXCIE1)|(1<<TXCIE1)|(1<<RXEN1)|(1<<TXEN1); /* 接收器与发送器使能*/
UCSR1C = (1<<UCSZ11)|(1<<UCSZ10); /* 设置帧格式: 8 个数据位, 1 个停止位 */
}
// 定义 USART1 接收变量**********************************************
#define RX_BUFFER_SIZE1 80
uchar rx_buffer1; //接收缓存
// USART1 写、读指示及缓存中数据的字节数
volatile uchar rx_wr_index1=0;
volatile uchar rx_rd_index1=0;
volatile uchar rx_counter1=0;
// USART1 接收中断*****************************************************
SIGNAL(SIG_UART1_RECV)
{
uchar Temp;
usart1_recv_flag=1;
SameFrameFlag1=3;
//判断有无错误,(FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN)=0X1C
if((UCSR1A&(FRAMING_ERROR|PARITY_ERROR|DATA_OVERRUN))==0)
{
rx_buffer1=UDR1; //接收数据至缓存区
if(++rx_wr_index1==RX_BUFFER_SIZE1)
rx_wr_index1=0; //缓存区满后写指示指向缓存区头
if(++rx_counter1==RX_BUFFER_SIZE1) //缓存区数据满后
rx_counter1=0; //清零字节记数值
}
else
Temp=UDR1;
}
// USART1 将缓存区数据读出到数组
uchar usart1_getstring(uchar *pGet)
{
uchar n=0;
while(rx_counter1)
{
*pGet++=rx_buffer1;
if(++rx_rd_index1==RX_BUFFER_SIZE1)
rx_rd_index1=0; //缓存数据读完后读指示指向缓存区头
asm volatile("cli");
--rx_counter1;
asm volatile("sei");
n++;
}
return n;
}
#define TX_BUFFER_SIZE1 80
uchar tx_buffer1; //发送缓存
// USART1 发送读写指示及缓存区字节数
volatile uchar tx_wr_index1=0;
volatile uchar tx_rd_index1=0;
volatile uchar tx_counter1=0;
// USART1 发送***************************************************************
SIGNAL(SIG_UART1_TRANS) // USART1 发送中断
{
if(tx_counter1)
{
tx_counter1-=1; //发送字节数减一
UDR1=tx_buffer1; //缓存区数据载入发送寄存器
if((++tx_rd_index1)==TX_BUFFER_SIZE1)
tx_rd_index1=0; //如果数据发送完读指示指向缓存区头
}
}
// USART1 将数据写入发送缓存区
void usart1_putchar(uchar c)
{
while(tx_counter1>=TX_BUFFER_SIZE1); //等待发送缓存中数据发送
asm volatile("cli"); //关全局中断
//如果缓存区有数据或正在发送数据
if(tx_counter1||((UCSR1A&DATA_REGISTER_EMPTY)==0))
{
tx_buffer1=c; //数据写入缓存区
if((++tx_wr_index1)==TX_BUFFER_SIZE1)tx_wr_index1=0;
tx_counter1+=1;
}
else
{
UDR1=c;
}
asm volatile("sei");
asm volatile("nop");
}
// USART1 发送ram中的字符串
void usart1_putramstring(uchar *str,uchar n)
{
while(n--)
{
usart1_putchar( *str++ );
}
}
// USART1 发送flash中的字符串
void usart1_putflashstring(char *str)
{
uchar temp=pgm_read_byte(str);
while(temp!='\0')
{
usart1_putchar( temp );
temp=pgm_read_byte(++str);
}
}
// USART1 发送n字符
void Usart1PutNChar(uchar *str,uchar n)
{
uchar i;
for(i=0;i<n;i++)
{
usart1_putchar( *str++ );
}
}
void sys_init(void)
{
usart0_init(9600);
usart1_init(9600);
asm("sei");
usart0_putflashstring(PSTR("Usart test,please wait!"));
usart0_putchar( '\r' );
usart0_putchar( '\n' );
SCH_Add_Task((void*)Usart0CommandDeal, 1, 2);
SCH_Add_Task((void*)Usart1CommandDeal, 0, 2);
SCH_Init_T0();
}
void Usart0CommandDeal(void)
{
static uchar *pUsartRece=Comm0Temp;
uchar Rcounter;
if(SameFrameFlag0)
SameFrameFlag0--;
if(usart0_recv_flag) //接收数据,是同一帧的数据合并
{
usart0_recv_flag=0;
Rcounter=usart0_getstring(pUsartRece);
if(SameFrameFlag0)
{
pUsartRece+=Rcounter;
if(pUsartRece-Comm0Temp>100)
{
Usart0PutNChar(Comm0Temp,pUsartRece-Comm0Temp);
pUsartRece=Comm0Temp;
}
}
}
if(SameFrameFlag0==0) //一帧接收完,处理数据
{
SameFrameFlag0=3;
Rcounter=pUsartRece-Comm0Temp;
pUsartRece=Comm0Temp;
Usart0PutNChar(Comm0Temp,Rcounter);
}
}
void Usart1CommandDeal(void)
{
static uchar *pUsartRece=Comm1Temp;
uchar Rcounter;
if(SameFrameFlag1)
SameFrameFlag1--;
if(usart1_recv_flag) //接收数据,是同一帧的数据合并
{
usart1_recv_flag=0;
Rcounter=usart1_getstring(pUsartRece);
if(SameFrameFlag1)
{
pUsartRece+=Rcounter;
if(pUsartRece-Comm1Temp>100)
{
Usart1PutNChar(Comm1Temp,pUsartRece-Comm1Temp);
pUsartRece=Comm1Temp;
}
}
}
if(SameFrameFlag1==0) //一帧接收完,处理数据
{
SameFrameFlag1=3;
Rcounter=pUsartRece-Comm1Temp;
pUsartRece=Comm1Temp;
Usart1PutNChar(Comm1Temp,Rcounter);
}
}
int main(void)
{
uchar Index;
sys_init();
while(1)
{
// 调度器调度任务
for (Index = 0; Index < SCH_MAX_TASKS; Index++)
{
if (SCH_tasks_G.RunMe)
{
(*SCH_tasks_G.pTask)(); // 运行任务
SCH_tasks_G.RunMe = 0; // 清除任务标志位
}
}
}
} asm volatile("cli");
--rx_counter0;
asm volatile("sei");
没仔细看,只看到这里,LZ的程序应该还是考虑挺周全的。 边用边改,现在感觉没有什么问题了才敢发上来,坛里高手太多了 敢于放上来, 即使被挑出毛病,也是很爽的 是的,还有我想把这个程序用到实际的产品中,让大家挑挑毛病更放心啊。 不错!!!!!!!!!!!! 求之不得,时间调度有什么好处啊,我没有发现啊,我觉得直接用比较方便啊 回复【5楼】zjr0411
-----------------------------------------------------------------------
个人觉得学习用的话可以,实际中可能不太实用,因为没有明显的优势。呵呵 学习~~~用双串口用调度比较好~ 学习. 学习~~ 感谢楼主,最近一直郁闷呢,两个串口同时使用一直搞不好,再次感谢!!! 一直怕定时器中断和串口中断起冲突。。。。。。。。 学习了!谢谢楼主! 学习啦!谢谢楼主
定时器中断和串口中断冲突了这么处理?或者说开定时器中断后,又使用外部中断那么应该怎么办呢? 希望高手赐教。{:smile:} 我可以剩下写代码的时间了!
谢谢!顺便可以测试下!{:sad:}
页:
[1]