zjr0411 发表于 2009-11-19 12:12:50

上传一个gcc的avr128的双串口程序,基于时间触发的调度程序

第一次上传示例,请大家有条件的测试一下,提出改进意见

应用于atmega128,winavr开发环境,版本20081205,直接打开编译即可。

点击此处下载 ourdev_504909.rar(文件大小:10K) (原文件名:UsartTest.rar)

zjr0411 发表于 2009-11-19 12:24:00

上传代码:


#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;                // 清除任务标志位
                        }
                }
        }
}

windy__xp 发表于 2009-11-19 12:39:00

asm volatile("cli");
--rx_counter0;
asm volatile("sei");

没仔细看,只看到这里,LZ的程序应该还是考虑挺周全的。

zjr0411 发表于 2009-11-19 12:54:06

边用边改,现在感觉没有什么问题了才敢发上来,坛里高手太多了

yajira 发表于 2009-11-19 13:42:18

敢于放上来, 即使被挑出毛病,也是很爽的

zjr0411 发表于 2009-11-19 17:59:11

是的,还有我想把这个程序用到实际的产品中,让大家挑挑毛病更放心啊。

hpdell 发表于 2010-3-20 17:51:51

不错!!!!!!!!!!!!

ahai0306 发表于 2010-3-27 15:37:41

求之不得,时间调度有什么好处啊,我没有发现啊,我觉得直接用比较方便啊

lbc___ 发表于 2010-3-27 15:44:27

回复【5楼】zjr0411
-----------------------------------------------------------------------

个人觉得学习用的话可以,实际中可能不太实用,因为没有明显的优势。呵呵

djl310 发表于 2010-4-13 15:05:14

学习~~~用双串口用调度比较好~

32446975 发表于 2010-8-24 08:55:00

学习.

cococ 发表于 2010-10-12 14:59:40

学习~~

BigSea001 发表于 2011-8-2 09:30:15

感谢楼主,最近一直郁闷呢,两个串口同时使用一直搞不好,再次感谢!!!

wangyj173 发表于 2011-8-9 16:35:56

一直怕定时器中断和串口中断起冲突。。。。。。。。

haigetianlong 发表于 2012-2-22 13:45:35

学习了!谢谢楼主!

孤傲龙杨 发表于 2012-9-1 12:47:44

学习啦!谢谢楼主

jacobson 发表于 2012-9-24 21:42:13

定时器中断和串口中断冲突了这么处理?或者说开定时器中断后,又使用外部中断那么应该怎么办呢? 希望高手赐教。{:smile:}

richwen 发表于 2012-9-28 16:37:06

我可以剩下写代码的时间了!
谢谢!顺便可以测试下!{:sad:}
页: [1]
查看完整版本: 上传一个gcc的avr128的双串口程序,基于时间触发的调度程序