|
这个程序要是加入错误处理就更好了.我上一个程序.加入错误处理的.这样在主程序轮询的时候只要检测错误情况就可以进行的数据收发,不需要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.接收缓冲区满后没有进行溢出处理.想加的朋友自己考虑.其实很简单,加一个标志位即可完成. |
|