搜索
bottom↓
回复: 17

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

[复制链接]

出200入0汤圆

发表于 2009-11-19 12:12:50 | 显示全部楼层 |阅读模式
第一次上传示例,请大家有条件的测试一下,提出改进意见

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

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

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

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

出200入0汤圆

 楼主| 发表于 2009-11-19 12:24:00 | 显示全部楼层
上传代码:


#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>

typedef unsigned char uchar;
typedef unsigned int  uint;
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[150];
uchar Comm1Temp[150];

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[SCH_MAX_TASKS];//        任务调度器数组

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[Index].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[Index].pTask  = pFunction;        // If we're here, there is a space in the task array
        SCH_tasks_G[Index].Delay  = DELAY;
        SCH_tasks_G[Index].Period = PERIOD;
        SCH_tasks_G[Index].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[Index].Delay == 0)
                {
                        //给可以被调度的任务设置标志位
                        //说明:任务运行标志位不具有存储功能,也就是说,如果在规定的
                        //      间隔内没有被运行,则机会丧失
                        SCH_tasks_G[Index].RunMe = 1;  // Inc. the 'Run Me' flag
                        SCH_tasks_G[Index].Delay = SCH_tasks_G[Index].Period;//将任务需要的延时装入
                }
                else
                {
                        SCH_tasks_G[Index].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[RX_BUFFER_SIZE0];        //接收缓存

// 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[rx_wr_index0]=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[rx_rd_index0];
                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[TX_BUFFER_SIZE0];                        //发送缓存

// 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[tx_rd_index0];                        //缓存区数据载入发送寄存器
                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[tx_wr_index0]=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[RX_BUFFER_SIZE1];        //接收缓存

// 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[rx_wr_index1]=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[rx_rd_index1];
                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[TX_BUFFER_SIZE1];                        //发送缓存

// 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[tx_rd_index1];                        //缓存区数据载入发送寄存器
                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[tx_wr_index1]=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[Index].RunMe)
                        {
                                (*SCH_tasks_G[Index].pTask)();                // 运行任务
                                SCH_tasks_G[Index].RunMe = 0;                // 清除任务标志位
                        }
                }
        }
}

出0入0汤圆

发表于 2009-11-19 12:39:00 | 显示全部楼层
asm volatile("cli");
--rx_counter0;
asm volatile("sei");

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

出200入0汤圆

 楼主| 发表于 2009-11-19 12:54:06 | 显示全部楼层
边用边改,现在感觉没有什么问题了才敢发上来,坛里高手太多了

出0入0汤圆

发表于 2009-11-19 13:42:18 | 显示全部楼层
敢于放上来, 即使被挑出毛病,也是很爽的

出200入0汤圆

 楼主| 发表于 2009-11-19 17:59:11 | 显示全部楼层
是的,还有我想把这个程序用到实际的产品中,让大家挑挑毛病更放心啊。

出0入0汤圆

发表于 2010-3-20 17:51:51 | 显示全部楼层
不错!!!!!!!!!!!!

出0入0汤圆

发表于 2010-3-27 15:37:41 | 显示全部楼层
求之不得,时间调度有什么好处啊,我没有发现啊,我觉得直接用比较方便啊

出0入0汤圆

发表于 2010-3-27 15:44:27 | 显示全部楼层
回复【5楼】zjr0411
-----------------------------------------------------------------------

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

出0入0汤圆

发表于 2010-4-13 15:05:14 | 显示全部楼层
学习~~~用双串口用调度比较好~

出0入0汤圆

发表于 2010-8-24 08:55:00 | 显示全部楼层
学习.

出0入0汤圆

发表于 2010-10-12 14:59:40 | 显示全部楼层
学习~~

出0入0汤圆

发表于 2011-8-2 09:30:15 | 显示全部楼层
感谢楼主,最近一直郁闷呢,两个串口同时使用一直搞不好,再次感谢!!!

出0入0汤圆

发表于 2011-8-9 16:35:56 | 显示全部楼层
一直怕定时器中断和串口中断起冲突。。。。。。。。

出0入0汤圆

发表于 2012-2-22 13:45:35 | 显示全部楼层
学习了!谢谢楼主!

出0入0汤圆

发表于 2012-9-1 12:47:44 | 显示全部楼层
学习啦!谢谢楼主

出0入0汤圆

发表于 2012-9-24 21:42:13 | 显示全部楼层
定时器中断和串口中断冲突了这么处理?  或者说开定时器中断后,又使用外部中断那么应该怎么办呢? 希望高手赐教。

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-6-11 00:21

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

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