搜索
bottom↓
回复: 80

一个AVR USART(RS232)低层驱动+中间层软件示例

[复制链接]

出0入0汤圆

发表于 2009-7-21 12:06:38 | 显示全部楼层
这个程序要是加入错误处理就更好了.我上一个程序.加入错误处理的.这样在主程序轮询的时候只要检测错误情况就可以进行的数据收发,不需要while的等待.并且是标准c些的,移植性比较好.

编译环境IAR4.20A


uart.h文件

#ifndef _UART_H_
#define        _UART_H_

#define        UART_TX_BUFF_SIZE        50
#define        UART_RX_BUFF_SIZE        20


#define        UART_FLAG_START_TX        BIT0


typedef        enum
{
        UART_ERR_TX_FULL        = 1,
        UART_ERR_RX_EMPTY        = 2,
        UART_ERR_NO_ERROR        = 3,
}UART_ERROR;


extern        void        InitUart();
extern        UART_ERROR        UartPutByte(pu8 pbyte);
extern        UART_ERROR        UartGetByte(pu8 pbyte);
extern        UART_ERROR        UartPutStream(pu8 pstream, u8 size);


#endif



uart.c文件

#include "uart.h"


static        u8        tx_buff[UART_TX_BUFF_SIZE];
static        u8        tx_in;
static        u8        tx_out;
static        u8        tx_cnt;


static        u8        rx_buff[UART_RX_BUFF_SIZE];
static        u8        rx_in;
static        u8        rx_out;
static        u8        rx_cnt;

static        u8        flag;



#pragma        vector=USART_TXC_vect
__interrupt        void        UartTxIntHandle()
{
        if(tx_cnt>0)
        {
                tx_cnt--;
                UDR        = tx_buff[tx_out++];
                if(tx_out==UART_TX_BUFF_SIZE)
                {
                        tx_out        = 0;
                }
        }
        else
        {
                flag        &= ~(1<<UART_FLAG_START_TX);
        }
}


#pragma        vector=USART_RXC_vect
__interrupt        void        UartRxIntHandle()
{
        u8        tmp;

        tmp        = UDR;

        if(rx_cnt<=UART_RX_BUFF_SIZE)
        {
                rx_cnt++;
                rx_buff[rx_in++]        = tmp;
                if(rx_in==UART_RX_BUFF_SIZE)
                {
                        rx_in        = 0;
                }
        }
}

void        InitUart()
{
        tx_in        = 0;
        tx_out        = 0;
        tx_cnt        = 0;

        rx_in        = 0;
        rx_out        = 0;
        rx_cnt        = 0;

        flag        = 0x00;

        UCSRB        |= (1<<RXCIE)|(1<<TXCIE)|(1<<RXEN)|(1<<TXEN);
        UBRRH        = 0;
        UBRRL        = 7;
}


UART_ERROR        UartPutByte(pu8 pbyte)
{
        CPU_REG_DEF;

        ENTER_CRITICAL();
        if(tx_cnt<=UART_TX_BUFF_SIZE)
        {
                if(flag&(1<<UART_FLAG_START_TX))
                {
                        tx_cnt++;
                        tx_buff[tx_in++]        = *pbyte;
                        if(tx_in==UART_TX_BUFF_SIZE)
                        {
                                tx_in        = 0;
                        }
                }
                else
                {
                        flag        |= 1<<UART_FLAG_START_TX;
                        UDR                = *pbyte;
                }
                EXIT_CRITICAL();

                return UART_ERR_NO_ERROR;
        }
        EXIT_CRITICAL();

        return UART_ERR_TX_FULL;
}


UART_ERROR        UartGetByte(pu8 pbyte)
{
        CPU_REG_DEF;

        ENTER_CRITICAL();
        if(rx_cnt>0)
        {
                rx_cnt--;
                *pbyte        = rx_buff[rx_out];
                EXIT_CRITICAL();

                if(++rx_out==UART_RX_BUFF_SIZE)
                {
                        rx_out        = 0;
                }

                return UART_ERR_NO_ERROR;
        }
        EXIT_CRITICAL();

        return UART_ERR_RX_EMPTY;
}

UART_ERROR        UartPutStream(pu8 pstream, u8 size)
{
        pu8        ptmp;

        if(size==0)
        {
                ptmp        = pstream;

                while(*ptmp++);

                size        = ptmp-pstream-1;
        }

        if(size>UART_TX_BUFF_SIZE-tx_cnt)
        {
                return UART_ERR_TX_FULL;
        }

        while(size--)
        {
                UartPutByte(pstream++);
        }

        return UART_ERR_NO_ERROR;
}


程序里需要几个类型及宏定义在以下的cpu.h中定义.

#ifndef _CPU_H_
#define        _CPU_H_

#define        CPU_FREQ                7372800L



// 无符号类型定义
typedef        unsigned char        u8;
typedef        unsigned int        u16;
typedef        unsigned long        u32;

// 只读无符号类型定义
typedef        unsigned char const   uc8;
typedef        unsigned int const            uc16;
typedef        unsigned long const    uc32;

// 无符号指针类型定义
typedef        unsigned char*        pu8;
typedef        unsigned int*        pu16;
typedef        unsigned long*        pu32;

// 不可变无符号类型定义
typedef        volatile unsigned char        vu8;
typedef        volatile unsigned int        vu16;
typedef        volatile unsigned long        vu32;

// 不可变只读无符号类型定义
typedef        volatile unsigned char const        vuc8;
typedef        volatile unsigned int const                vuc16;
typedef        volatile unsigned long const        vuc32;

// 有符号类型定义
typedef        signed char                s8;
typedef        signed int                s16;
typedef        signed long                s32;

// 只读有符号类型定义
typedef        signed char const        sc8;
typedef        signed int const        sc16;
typedef        signed long const        sc32;

// 有符号指针类型定义
typedef        signed char*        ps8;
typedef        signed int*        ps16;
typedef        signed long*        ps32;

// 不可变有符号类型定义
typedef        volatile signed char        vs8;
typedef        volatile signed int        vs16;
typedef        volatile signed long        vs32;

// 不可变只读有符号类型定义
typedef        volatile signed char const        vsc8;
typedef        volatile signed int const        vsc16;
typedef        volatile signed long const        vsc32;

// 浮点类型定义
typedef        float                fp32;

// 布尔类型定义
//typedef         unsigned char        bool;

// cpu寄存器类型定义
typedef        unsigned char        c_reg;

// 标志位定义
typedef unsigned char        FLAG;


typedef        enum
{
        FALSE        = 0,
        TRUE        = !FALSE
}bool;


#define        BIT0        0
#define        BIT1        1
#define        BIT2        2
#define        BIT3        3
#define        BIT4        4
#define        BIT5        5
#define        BIT6        6
#define        BIT7        7

#define        FLAG0        0x01
#define        FLAG1        0x02
#define        FLAG2        0x04
#define        FLAG3        0x08
#define        FLAG4        0x10
#define        FLAG5        0x20
#define        FLAG6        0x40
#define        FLAG7        0x80


#define        setb(value, offset)        value|=1<<(offset)
#define        clrb(value, offset)        value&=~(1<<(offset))
#define        cplb(value, offset)        value^=1<<(offset)
#define        getb(value, offset)        (value&(1<<(offset)))

#define        MSB8        0x80
#define        LSB8        0x01
#define        MSB16        0x8000
#define        LSB16        0x0001
#define        MSB32        0x80000000
#define        LSB32        0x00000001





#define        CPU_REG_DEF        c_reg cpu_reg

#define        ENTER_CRITICAL()        cpu_reg=SREG;        \
                        __enable_interrupt()

#define        EXIT_CRITICAL()        SREG=cpu_reg



#endif




调用示例:

u8    tmp;

if(UartGetByte(&tmp)==UART_ERR_NO_ERROR)
{
      缓冲区中有数据进行协议或其他处理......
}
else
{
      缓冲区中没有数据执行错误代码,或者else可以省略,只处理有数据的情况.
}

发送示例:
发送一般都发送数据流,所以字节发送一般不需要.把发送字节函数开放出来其实没有必要.
u8 tmpbuff[N];
...
if(UartPutStream(tmpbuff, 2)==UART_ERR_NO_ERROR)
{
    发送成功,进行成功处理
}
else
{
    发送失败,可以重新发送或是其他处理
}

2.发送字符串
if(UartPutStream("hello", 0)==UART_ERR_NO_ERROR)
{
    发送成功,进行成功处理
}
else
{
    发送失败,可以重新发送或是其他处理
}
将参数2设置为0函数认为发送字符串.


说明:发送和接收的变量都可以使用结构体来完成.如:
typedef struct
{
    pu8 buff;
    u8  in;
    u8  out;
    u8  cnt;
    u8  flag;
}UART_STRUCT;


static        u8        tx_buff[UART_TX_BUFF_SIZE];
static        u8        rx_buff[UART_RX_BUFF_SIZE];
static     UART_STRUCT  TxStruct;
static     UART_STRUCT  RxStruct;

void InitUart()
{
    ....
    TxStruct.buff = tx_buff;
    TxStruct.in   = 0;
    TxStruct.out  = 0;
    TxStruct.cnt  = 0;
    TxStruct.flag = 0x00;

    RxStruct.buff = rx_buff;
    ....
}

或者in,out都用指针来做.

之所以没使用结构体或者使用指针来做是因为,为了提高底层函数的执行速度,以及节约占用SRAM的空间.

由于8位mcu的代码空间和sram比较小,所以做成分立的变量不进行结构封装,可以省出一些flash及其sram空间留给更需要的地方.并且底层函数只留出几个接口(UartGetByte(),UartPutStream())在使用的时候不需要考虑内部的架构.可以更好的偏向面向对象编程思想.

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

本版积分规则

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

GMT+8, 2024-5-5 12:02

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

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