远离代码 发表于 2014-8-10 19:43:58

这个结构化串口通信怎么理解呀?看的一头雾水,求教大神

/************************************************
文件:sio.c
用途:结构化串口通信程序
************************************************/
#include "config.h"

#if USEUART0
siocirqueue RTbuf_UART0;//如果选用串口0,定义一组发送,接受数组RTbuf_UART0
#endif
#if USEUART1
siocirqueue RTbuf_UART1;
#endif

#if (CPU_TYPE == M32)||(CPU_TYPE == M16)||(CPU_TYPE == M8)
#define USEUART0TRUE
#define USEUART1FALSE
#define iv_USART0_RXC   iv_USART_RXC
#define iv_USART0_TXC   iv_USART_TXC
#define UDR0          UDR
#define UCSR0A    UCSRA
#define UCSR0B    UCSRB
#define UCSR0C          UCSRC
#define UBRR0H          UBRRH
#define UBRR0L          UBRRL
#define RXCIE0          RXCIE
#define TXCIE0          TXCIE
#endif


/*********************************************************************************************************
** 函数名称: Com_init
** 功能描述: 初始化串行口
** 输 入:
** 全局变量: 无
** 调用模块: Com_baudrate
** 说明:
** 注意:
********************************************************************************************************/
void Com_init (void)
{
//WDR(); //喂狗
//CLI();                     // 关中断
#if USEUART0
Tbuf_init(&RTbuf_UART0);            //初始化接收缓冲
Rbuf_init(&RTbuf_UART0);
UCSR0B = 0x00; //disable while setting baud rate
UCSR0A=0x00;

#if CPU_TYPE <= M32
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
UCSR0B = (1<<RXCIE)|(1<<TXCIE)|(1<<RXEN)|(1<<TXEN);// RXCIE=1;TXCIE=1;UDREIE=0;RXEN=1;TXEN=1
#else
UCSR0C=0x06;//8 DATA ,1 STOP, NO PARITY
UCSR0B = (1<<RXCIE0)|(1<<TXCIE0)|(1<<RXEN0)|(1<<TXEN0);// RXCIE=1;TXCIE=1;UDREIE=0;RXEN=1;TXEN=1
#endif

#endif


#if USEUART1
Tbuf_init(&RTbuf_B);            //初始化接收缓冲
Rbuf_init(&RTbuf_B);
UCSR1B = 0x00; //disable while setting baud rate
UCSR1A = 0x00;
UCSR1C = 0x06;
UCSR1B = 0xD8;
#endif
Com_baudrate (9600);               //

//SEI();                     // 开中断
}
/*********************************************************************************************************
** 函数名称: Com_baudrate
** 功能描述: 利用定时器T1产生由参数baudrate指定的波特率
** 输 入: baudrate指定的波特率
** 全局变量: 无
** 调用模块: 无
** 说明:
** 注意:
********************************************************************************************************/
void Com_baudrate (unsigned int baudrate) {
unsigned int tmp;
tmp= F_CPU/baudrate/16-1;
#if USEUART0
UBRR0H=(unsigned char)(tmp>>8);
UBRR0L=(unsigned char)tmp;
#endif
#if USEUART1
UBRR1H=(unsigned char)(tmp>>8);
UBRR1L=(unsigned char)tmp;
#endif
}
/*********************************************************************************************************
** 函数名称: Com_putchar
** 功能描述: 从串行口输出一个字符c
** 输 入: c:输出字符
** 输出       : 0:失败 1:成功
** 全局变量: 无
** 调用模块:
** 说明:
** 注意:
********************************************************************************************************/
unsigned char Com_putchar (unsigned char c,siocirqueue *RTbuf) {
//WDR(); //喂狗
if (Tbuf_full(RTbuf))
   return(0);
else{
        Tbuf_putchar(c,RTbuf);                                // 将数据加入到发送缓冲区并开中断
        return(1);
        }
}
/*********************************************************************************************************
** 函数名称: Com_putstring
** 功能描述: 从串行口输出一个字符串
** 输 入: p:指向输出字符串 len:输出长度
** 输出       :
** 全局变量: 无
** 调用模块:
** 说明:
** 注意:
********************************************************************************************************/
void Com_putstring (unsigned char *p,unsigned char len,siocirqueue *RTbuf) {
unsigned char i;
//WDR(); //喂狗
if (len!=0 ){
        for(i=0;i<len;i++)
        while(Com_putchar(p,RTbuf)==0);//WDR(); //喂狗;
        }
        else {
                do{
                        while(Com_putchar(*p,RTbuf)==0);//WDR(); //喂狗;
                        }while(*p++!='\n');
        }
       
}
/*********************************************************************************************************
** 函数名称: Com_getchar
** 功能描述: 从串行口输入一个字符
** 输 入: mode:0不需等待,在调用函数前检测Com_R_count的值
**            1 等待数据到来
** 输出       : 读入的字符
** 全局变量: 无
** 调用模块:
** 说明:
** 注意:
********************************************************************************************************/

unsigned char Com_getchar (unsigned char mode,siocirqueue *RTbuf) {
//WDR(); //喂狗
//    Delay(Delay_Comget,MaxLimit_Comget_Delay);
//        if (mode>0) while(Com_R_count(RTbuf)==0 && !DelayOvf(Delay_Comget))//WDR(); //喂狗;
//        if (DelayOvf(Delay_Comget))
//          return 0;    //时间超时
//        else
          
                while(!Com_R_count(RTbuf));
                return (Rbuf_getchar(RTbuf));// 串行口输入正确,返回输入的字符
}



void Com_Rbuf_Clear(siocirqueue *RTbuf){
        Rbuf_init(RTbuf);
}



unsigned char Com_getstring (unsigned char *p,unsigned char len,siocirqueue *RTbuf)
{
unsigned char i=0;
//WDR(); //喂狗
if (len>0 )
{
        for(i=0;i<len;i++){
                //WDR(); //喂狗
                *p++=Com_getchar(1,RTbuf);
                }
        return(len);
}
else
{
                do{
                                *p++=Com_getchar(1,RTbuf);
                                i++;
                                //WDR(); //喂狗
                        }while(*(p-1)!='\n');
//                        *p++=Com_getchar(1,RTbuf);
//                        *(p)=0;
                return(i);
                }
       
}
/*********************************************************************************************************
** 函数名称: Com_R_count
** 功能描述: 返回接收缓冲区字符个数函数
** 输 入:
** 输出       : 字符个数
** 全局变量: 无
** 调用模块:
** 说明:
** 注意:
********************************************************************************************************/
unsigned char Com_R_count(siocirqueue *RTbuf){
return RTbuf->R_count;
}
/*********************************************************************************************************
** 函数名称: Rbuf_init
** 功能描述: 接收缓冲区初始化
** 输 入:
** 输出       :
** 全局变量: 无
** 调用模块:
** 说明:
** 注意:
********************************************************************************************************/
void Rbuf_init(siocirqueue *RTbuf)
{
        RTbuf->R_front=0;
        RTbuf->R_rear=0;
    RTbuf->R_count=0;
        RTbuf->R_overflow=0;
}
/*********************************************************************************************************
** 函数名称: Tbuf_init
** 功能描述: 发送缓冲区初始化
** 输 入:
** 输出       :
** 全局变量: 无
** 调用模块:
** 说明:
** 注意:
********************************************************************************************************/
void Tbuf_init(siocirqueue *RTbuf){
        RTbuf->T_front=0;
        RTbuf->T_rear=0;
    RTbuf->T_count=0;
        RTbuf->T_disabled=1;
        }
/*********************************************************************************************************
** 函数名称: Rbuf_empty
** 功能描述: 接收缓冲区判空
** 输 入:
** 输出       :TRUE 空 FALSE 非空
** 全局变量: 无
** 调用模块:
** 说明:
** 注意:
********************************************************************************************************/
unsigned char Rbuf_empty(siocirqueue *RTbuf){
        return RTbuf->R_count==0;
        }
/*********************************************************************************************************
** 函数名称: Tbuf_empty
** 功能描述: 发送缓冲区判空
** 输 入:
** 输出       :TRUE 空 FALSE 非空
** 全局变量: 无
** 调用模块:
** 说明:
** 注意:
********************************************************************************************************
unsigned char Tbuf_empty(void){
        return RTbuf->T_count==0;
        }
/*********************************************************************************************************
** 函数名称: Rbuf_full
** 功能描述: 接收缓冲区判满
** 输 入:
** 输出       :TRUE 满 FALSE 非满
** 全局变量: 无
** 调用模块:
** 说明:
** 注意:
********************************************************************************************************
unsigned char Rbuf_full (void){
        return RTbuf->R_count==RBUF_SIZE;
        }
/*********************************************************************************************************
** 函数名称: Tbuf_full
** 功能描述: 发送缓冲区判满
** 输 入:
** 输出       :TRUE 满 FALSE 非满
** 全局变量: 无
** 调用模块:
** 说明:
** 注意:
********************************************************************************************************/
unsigned char Tbuf_full(siocirqueue *RTbuf){
        return RTbuf->T_count==TBUF_SIZE;
        }
/*********************************************************************************************************
** 函数名称: Rbuf_putchar
** 功能描述: 把一个字符放入接收缓冲区
** 输 入:
** 输出       :
** 全局变量: 无
** 调用模块:
** 说明:
** 注意:
********************************************************************************************************
voidRbuf_putchar (unsigned char x){
        if(!Rbuf_full()){
                REV_DIS();
                RTbuf->R_count++;
                RTbuf->R_buf=x;
                RTbuf->R_rear=(RTbuf->R_rear+1) % RBUF_SIZE;
                REV_EN();
        }
}
/*********************************************************************************************************
** 函数名称: Tbuf_putchar
** 功能描述: 把一个字符放入发送缓冲区
** 输 入:
** 输出       :
** 全局变量: 无
** 调用模块:
** 说明:
** 注意:
********************************************************************************************************/
void Tbuf_putchar(unsigned char x,siocirqueue *RTbuf){
        if(!Tbuf_full(RTbuf)){
                TXC_DIS();
                if (RTbuf->T_disabled)
                        {
                        UDR0=x;
                        RTbuf->T_disabled=0;
                        }
                else
                        {
                        RTbuf->T_count++;
                        RTbuf->T_buf=x;
                        RTbuf->T_rear=(RTbuf->T_rear+1) % TBUF_SIZE;
                        }
                TXC_EN();
        }
}
/*********************************************************************************************************
** 函数名称: Rbuf_getstring
** 功能描述: 从接收缓冲区返回当前子串指针
** 输 入:
** 输出       :当前子串指针
** 全局变量: 无
** 调用模块:
** 说明:
** 注意:
********************************************************************************************************
unsigned char * Rbuf_getstring(void){
        return (RTbuf->R_buf);
}
/*********************************************************************************************************
** 函数名称: Tbuf_getstring
** 功能描述: 从发送缓冲区返回当前子串指针
** 输 入:
** 输出       :当前子串指针
** 全局变量: 无
** 调用模块:
** 说明:
** 注意:
********************************************************************************************************
unsigned char * Tbuf_getstring(void){
        return (RTbuf->T_buf);
}
/*********************************************************************************************************
** 函数名称: Rbuf_putchar
** 功能描述: 从接收缓冲区读一个字符
** 输 入:
** 输出       :读字符
** 全局变量: 无
** 调用模块:
** 说明:
** 注意:
********************************************************************************************************/
unsigned char Rbuf_getchar(siocirqueue *RTbuf){
        unsigned char Btemp=0;
        if (!Rbuf_empty(RTbuf)){
                Btemp=RTbuf->R_buf;
                REV_DIS();
                RTbuf->R_count--;
                RTbuf->R_front=(RTbuf->R_front+1) % RBUF_SIZE;
                REV_EN();
                }
        return (Btemp);
       
}
/*********************************************************************************************************
** 函数名称: Tbuf_getchar
** 功能描述: 从发送缓冲区读一个字符
** 输 入:
** 输出       :读字符
** 全局变量: 无
** 调用模块:
** 说明:
** 注意:
********************************************************************************************************
unsigned char Tbuf_getchar(void){
        unsigned char Btemp;
        if (!Tbuf_empty()){
                Btemp=RTbuf->T_buf;
                TXC_DIS();
                RTbuf->T_count--;
                RTbuf->T_front=(RTbuf->T_front+1) % TBUF_SIZE;
                TXC_EN();
                return (Btemp);
        }
}
*/

/******************************* 中断处理函数 ***************************
* 功能:完成数据得的接收和发送
***********************************************************************/
#if USEUART0
#pragma interrupt_handler uart0_rx_isr:iv_USART0_RXC
void uart0_rx_isr(void)
{
unsigned char status,data;
siocirqueue *RTbuf;
RTbuf=&RTbuf_UART0;
// CLI();
status=UCSR0A;
data=UDR0;
//WDR(); //喂狗
if((status & (FRAMING_ERROR | DATA_OVERRUN))==0)
        {
        if(RTbuf->R_count<RBUF_SIZE){
                RTbuf->R_count++;
                RTbuf->R_buf=data;
                RTbuf->R_rear=(RTbuf->R_rear+1) % RBUF_SIZE;
                }
        else
           {
           RTbuf->R_overflow=1;
           }
        }
//SEI();
}
       
#pragma interrupt_handler uart0_tx_isr: iv_USART0_TXC
void uart0_tx_isr(void)
{
//CLI();
siocirqueue *RTbuf;
//WDR(); //喂狗
RTbuf=&RTbuf_UART0;
if (RTbuf->T_count>0){
        UDR0=RTbuf->T_buf;
        RTbuf->T_count--;
        RTbuf->T_front=(RTbuf->T_front+1) % TBUF_SIZE;
        }
else RTbuf->T_disabled=1;
//SEI();
}
#endif

#if USEUART1
#pragma interrupt_handler uart1_rx_isr:iv_USART1_RXC
void uart1_rx_isr(void)
{
unsigned char status,data;
siocirqueue *RTbuf;
RTbuf=&RTbuf_B;
// CLI();
//WDR(); //喂狗
status=UCSR1A;
data=UDR1;
if((status & (FRAMING_ERROR | DATA_OVERRUN))==0)
        {
        if(RTbuf->R_count<RBUF_SIZE){
                RTbuf->R_count++;
                RTbuf->R_buf=data;
                RTbuf->R_rear=(RTbuf->R_rear+1) % RBUF_SIZE;
                }
        else
           {
           RTbuf->R_overflow=1;
           }
        }
//SEI();
}
       
#pragma interrupt_handler uart1_tx_isr: iv_USART1_TXC
void uart1_tx_isr(void)
{
//CLI();
siocirqueue *RTbuf;
//WDR(); //喂狗
RTbuf=&RTbuf_B;
if (RTbuf->T_count>0){
        UDR1=RTbuf->T_buf;
        RTbuf->T_count--;
        RTbuf->T_front=(RTbuf->T_front+1) % TBUF_SIZE;
        }
else RTbuf->T_disabled=1;
//SEI();
}
#endif

attach://211499.pdf
attach://211496.zip

unifax001 发表于 2014-8-10 20:20:34

你自己都叫做“远离代码了”也就远离吧 也不说说具体情况 哪里不懂 就考一段又长又臭的代码 谁有闲工夫给你分析啊

远离代码 发表于 2014-8-10 21:17:29

unifax001 发表于 2014-8-10 20:20
你自己都叫做“远离代码了”也就远离吧 也不说说具体情况 哪里不懂 就考一段又长又臭的代码 谁有闲工夫给你 ...

      
/*********************************************************************************************************
** 函数名称: Com_putchar
** 功能描述: 从串行口输出一个字符c
** 输 入: c:输出字符
** 输出       : 0:失败 1:成功
** 全局变量: 无
** 调用模块:
** 说明:
** 注意:
********************************************************************************************************/
unsigned char Com_putchar (unsigned char c,siocirqueue *RTbuf) {
//WDR(); //喂狗
if (Tbuf_full(RTbuf))
   return(0);
else{
        Tbuf_putchar(c,RTbuf);                                // 将数据加入到发送缓冲区并开中断
        return(1);
        }
}
这是结构体的定义,
#define RBUF_SIZE        100
#define TBUF_SIZE   100
typedef struct{
unsigned char R_front;
unsigned char R_rear;
unsigned char R_count;
unsigned char R_overflow;
unsigned char R_buf;
unsigned char T_front;
unsigned char T_rear;
unsigned char T_count;
unsigned char T_buf;
unsigned char T_disabled;
}siocirqueue;//定义结构体siocirqueue

Com_putchar函数返回0的目的只是为了说明 RTbuf->T_count已经存满了,不能再继续存储了?还有结构体siocirqueue定义的目的是什么呀?
        unsigned char Tbuf_full( siocirqueue *RTbuf)
{
       return RTbuf->T_count==TBUF_SIZE;
        }

lcw_swust 发表于 2014-8-11 17:07:53

本帖最后由 lcw_swust 于 2014-8-11 17:09 编辑

这个程序的意思大概是利用软件模拟FIFO(先进先出队列),自动的将串口数据作缓冲处理。
siocirqueue 内有两个FIFO,一个用于发送,一个用于接收。
用FIFO的好处:可以节省CPU。
例如:
Com_putchar 可以在很短的时间执行完,因为它只是往数组内存入一个字节数据,
真正往UDR写入送数据是在发送中断内处理的,也会在很短的时间内处理好。

654705188 发表于 2014-8-11 17:23:13

结构体siocirqueue定义的目的是方便引用处理,每个字节的意义更明确,而且修改起来更方便。
我一般喜欢这样用
#define PSENDDATA(p)         ((SENDDATA_Type *)(u32)p)
#define PRECVDATA(p)         ((RECVDATA_Type *)(u32)p)

typedef struct _senddata_
{
u8HDR;
u8SNUM;
u8ID;
u8RET;
u8CMD;
u16 LEN;
u8DATA;
}SENDDATA_Type;

typedef struct _recvdata_
{
u8HDR;
u8SNUM;
u8ID;
u8STATUS;
u8CMD;
u16 LEN;
u8DATA;
}RECVDATA_Type;

static u8 Snum=0;
s16 Fill_Senddata(u8 *data,u8 cmd,u8 *senddta,u16 sdatalen)
{
Snum++;
PSENDDATA(data)->HDR=0xAA;
PSENDDATA(data)->SNUM=Snum;
memcpy(PSENDDATA(data)->ID,PARAM(Param)->REG,PARAM_REG_LEN);
PSENDDATA(data)->RET=0x55;
PSENDDATA(data)->CMD=cmd;
PSENDDATA(data)->LEN=sdatalen;
memcpy(PSENDDATA(data)->DATA,senddta,sdatalen);
Set_Senddata_CRCEND(data,CRC16(data,sdatalen+18));

return sdatalen+21;
}

s16 Check_Recvdata(u8 *data,u8 cmd,u8 *status)
{
u16 crc=0;
if((PRECVDATA(data)->HDR!=0xAA)||(PRECVDATA(data)->DATA[(PRECVDATA(data)->LEN)+2]!=0xBB))
return ERR_HEAD;
crc= (PRECVDATA(data)->DATA)+((u16)(PRECVDATA(data)->DATA[(PRECVDATA(data)->LEN)+1])<<8);
if(CRC16(data,(PRECVDATA(data)->LEN)+18)!=crc)
return ERR_CRC;
if(PRECVDATA(data)->SNUM!=Snum)
return ERR_SNUM;
if(memcmp(PRECVDATA(data)->ID,PARAM(Param)->REG,PARAM_REG_LEN)!=0)
return ERR_ID;//ID错误
if(PRECVDATA(data)->CMD!=cmd)
return ERR_CMD;
if(PRECVDATA(data)->STATUS==0x55)
return ERR_RECV;
if(PRECVDATA(data)->STATUS!=ERR_NO)
*status=PRECVDATA(data)->STATUS;
return ERR_NO;
}

但要注意双字节u16的或四字节u32的数据类型开始的地址必须是偶地址。

远离代码 发表于 2014-8-11 21:24:23

lcw_swust 发表于 2014-8-11 17:07
这个程序的意思大概是利用软件模拟FIFO(先进先出队列),自动的将串口数据作缓冲处理。
siocirqueue 内有 ...

tks,拜读了你的帖子,真大牛
页: [1]
查看完整版本: 这个结构化串口通信怎么理解呀?看的一头雾水,求教大神