⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 test.c

📁 无线双向通讯
💻 C
字号:
#include <reg51.h>
#include "string.h"


sbit LED1 = P1^2;
sbit LED2 = P1^4;
sbit LED3 = P1^3;
//sbit LED1 = P3^6;
//sbit LED2 = P3^7;
sbit W_IN = P3^2;
sbit W_OUT = P3^4;

unsigned char w_timer=0;
unsigned int jiffies=0,x=0;
void clock_timer(void) interrupt 1 using 1{
    jiffies++;
    //if(x++==500){x=0;
    w_timer++;//};
}

void clock_init(void){
    jiffies = 0;
    TMOD=0x02;
//  TH0=TL0=0x9b;//12M
//  TH0=TL0=0x7a;//16M
//  TH0=TL0=0x75;//16.59M
//  TH0=TL0=0x72;//17M
//  TH0=TL0=0x37;//24M
    TH0=TL0=0x40;//22M
    EA=1;
    ET0=1;

    TR0=1;
}
void init_serialcomm(void)
{
    SCON  = 0x50;       //SCON: serail mode 1, 8-bit UART, enable ucvr 
    TMOD |= 0x20;       //TMOD: timer 1, mode 2, 8-bit reload 
    PCON |= 0x80;       //SMOD=1; 
    TH1   = 0xFF;       //Baud:4800  fosc=11.0592MHz  :f4
    //IE   |= 0x90;       //Enable Serial Interrupt 
    TR1   = 1;          // timer 1 run
    RI=0;
    TI=1; 
}

void serial_out(unsigned char d){
    while(!TI);
    TI=0;
    SBUF=(d);
}

//等待指定长度的串行数据到达,超时值为每两个字节之间的间隔时间而非等待整个串的时间.
//超时单位为time_out * 100uS
bit wait_serial(unsigned char *p, unsigned char len, unsigned char time_out){
    unsigned int time=jiffies;
    unsigned char n=0;
    do{
        if (RI){
            p[n++]=SBUF;
            RI=0;
            if(n==len)
                return 0;
            time=jiffies;
        }
    }while(jiffies-time < time_out);
    return 1;
}

#define W_LP 6  //低电平/前引导
#define W_HP 12 //高电平
#define W_FS 18 //引导/结束
#define HEAD_CODE 100   //前导码个数

#define DEBUG 0

#define W_BUF_LEN 24
unsigned char w_buf[W_BUF_LEN];

unsigned char w_recv_step=0;
unsigned char w_recv_data;
unsigned char w_recv_last_time; //上一次翻转的时间
unsigned char w_recv_width; //脉冲宽度
bit w_recv_status,w_recv_last_status;
bit recv_over = 0;
#define START_RECV() {w_recv_step=0; recv_over=0;}
#define STOP_RECV() {recv_over=1;}
void w_recv(void){
    //正式写程序时,应在调用该函数前就做检测,以节省时间.以下检测应删去.
    if(recv_over)
        return;

    w_recv_status=W_IN;
    LED1=!w_recv_status;

    if (w_recv_last_status == w_recv_status){//信号脚无变化,无信号到达,直接返回,返回前仅处理超时.
        if (w_recv_step == 0)//w_recv_step==0时无需处理超时
            return;
        w_recv_width = w_timer - w_recv_last_time;
        if (w_recv_width > W_FS + W_LP/2){//超时处理
            w_recv_step = 0;
#if DEBUG
            //serial_out(0x53);
            //serial_out(w_recv_width);
#endif
        }
        return;
    }
    w_recv_last_status = w_recv_status;//记下本次电平值
    w_recv_width = w_timer - w_recv_last_time;//如果上一个信号已完成,记录信号宽度,如果当前为第一个信号,该计算结果不使用
    w_recv_last_time = w_timer;//新的信号到达,更新计时器

    if (w_recv_step == 0){//目前所处理的信号为第一个信号,不需作后续处理,因为无上一个信号信息.
        w_recv_step = 1;
        return;
    }

    //step 1: 等待前引导信号到来
    if(w_recv_step == 1){
        if(w_recv_width > W_LP - W_LP/2 && w_recv_width < W_LP + W_LP/2)//前引导脉冲到来,宽度约为8,重复发送,直到发送引导脉冲
            w_recv_step = 2;
        return;
    }

    //等待前引导信号结束及等待引导信号到来
    if(w_recv_step == 2){
        if(w_recv_width > W_LP - W_LP/2 && w_recv_width < W_LP + W_LP/2)//前引导脉冲还未结束,等待
            return;
        if(w_recv_width > W_FS - W_LP/2 && w_recv_width < W_FS + W_LP/2)//引导脉冲到来,宽度约为16
            w_recv_step = 3;
        else{
            w_recv_step = 0;
#if DEBUG
            serial_out(0x54);
            serial_out(w_recv_width);
#endif
        }
        return;
    }

    //读取一字节
    if(w_recv_step > 2 && w_recv_step < 3 + W_BUF_LEN * 8){//step 3 --- step 10: 取回8位数据
        w_recv_data >>= 1;
    
        if(w_recv_width > W_LP - W_LP/2 && w_recv_width < W_LP + W_LP/2)
            w_recv_data &= 0x7f;
        else
        if(w_recv_width > W_HP - W_LP/2 && w_recv_width < W_HP + W_LP/2)
            w_recv_data |= 0x80;
        else{
            w_recv_step = 0;
#if DEBUG
            serial_out(0x56);
            serial_out(w_recv_width);
#endif
        }
        if(((w_recv_step - 3) & 7) == 7)
            w_buf[(w_recv_step - 3) >> 3] = w_recv_data;
    }

    if(w_recv_step == 3 + W_BUF_LEN * 8){//step 11 : 结束
        if(w_recv_width > W_FS - W_LP/2 && w_recv_width < W_FS + W_LP/2)//等待结束脉冲,宽度约为20,未收到该信号则为出错
            recv_over = 1;//serial_out(0xaa);
        else
            serial_out(0x55);
    }

    w_recv_step++;
}

unsigned int w_send_step=0;
unsigned char w_send_data;
unsigned char w_send_last_time; //上一次翻转的时间
unsigned char w_send_width; //脉冲宽度
bit send_over=1;
#define START_SEND() {w_send_step=0; send_over=0;}
#define STOP_SEND() {send_over=1;}
void w_send(){
    //正式写程序时,应在调用该函数前就做检测,以节省时间.以下检测应删去.
    if(send_over)
        return;

    if(w_send_step == HEAD_CODE + 2 + W_BUF_LEN * 8)//数据发送完毕
        send_over = 1;

    if (w_send_step == 0){
        w_send_step = 1;
        w_send_width = W_LP;
        W_OUT = 0;
        LED2 = 0;
        return;
    }

    if(w_timer - w_send_last_time < w_send_width)
        return;

    w_send_step++;
    w_send_last_time = w_timer;
    W_OUT = !W_OUT;
    LED2 = !LED2;

    if(w_send_step == HEAD_CODE)
        w_send_width = W_FS;

    if(w_send_step > HEAD_CODE && w_send_step < HEAD_CODE + 1 + W_BUF_LEN * 8){
        if(((w_send_step - (HEAD_CODE + 1)) & 7) == 0)
            w_send_data = w_buf[(w_send_step - (HEAD_CODE + 1)) >> 3];
        if(w_send_data & 1)
            w_send_width = W_HP;
        else
            w_send_width = W_LP;
        w_send_data >>= 1;
    }

    if(w_send_step == HEAD_CODE + 1 + W_BUF_LEN * 8)
        w_send_width = W_FS;

}

sys_init(){
    clock_init();
    init_serialcomm();
}

//pdata unsigned char this_node_id = 0x11;
unsigned char this_node_id = 0x11;

typedef struct pack_head_s{
    unsigned char source_id;
    unsigned char target_id;
    unsigned char package_len;
    unsigned char check_sum;
}package_head_t;
typedef struct package_s{
    package_head_t head;
    unsigned char package_data[1];
}package_t;

//发送函数返回值
#define ERROR_SEND_BUSY 0x10    //前一次发送未完成
#define ERROR_SEND_NULL 0x23        //发送包长为0,错误包

//接收函数返回值
#define ERROR_RECV_EMPTY 0x20   //当前未收到数据
#define ERROR_RECV_CHECKSUM 0x21    //校验和错误
#define ERROR_RECV_NULL 0x22        //收到包长为0,错误包


//由于计算校验合会占用大量时间,因此在调用该函数时接收程序后台部分会受影响,可能造成正在接收的数据报文丢失.
//发送程序后台部分同样会受影响,但由于此时后台发送肯定是空闲,所以忽略影响.
//所以,调用原则是:发送时要确认发送与接收已全部停止
unsigned char send_package(package_t *package){
    unsigned char check_sum;
    unsigned char len;
    unsigned char *p;

    package->head.package_len = W_BUF_LEN;//目前是将数据包长度定死,设包长的目的是为了将来扩展.

    len = package->head.package_len;    //为将来而设.今后发送包长可能在进放该函数前设定.
    if (len == 0)
        return ERROR_SEND_NULL;

    //填写报文头
    package->head.source_id = this_node_id;

    //计算校验和,计算完后,报文所有字节(包括报文头)之和应为0
    package->head->check_sum = 0;
    check_sum = 0;
    p = (unsigned char*)package;
    do{
        check_sum += *p;
        p++;
    }while(--len);
    package->head->check_sum = ~check_sum;

    //发送
    START_SEND();

    while(!send_over)
        w_send();

    return 0;
}

//由于计算校验合会占用大量时间,因此在调用该函数时发送程序后台部分会受影响,可能造成正在发送的数据报文时序错乱.
//接收程序后台部分同样会受影响,但由于此时后台接收肯定是已经完成的状态,所以忽略影响.
//所以,调用原则是:发送时要确认发送程序已停止
unsigned char recv_package(package_t *package){
    unsigned char check_sum;
    unsigned char len;
    unsigned char *p;

    if (len == 0)
        return ERROR_RECV_NULL;

    //计算校验和
    len = package->head.package_len;
    check_sum = 0;
    p = (unsigned char*)package;
    do{
        check_sum += *p;
        p++;
    }while(--len);
    if(check_sum)
        return ERROR_RECV_CHECKSUM;

    return 0;
}

void sys_thread(){
    if(!recv_over)
        w_recv();
    //后面加上键盘扫描等驱动程序,但所有代码执行最长时间不得高于100微秒
}

typedef struct command_s{
    unsigned char command_id;
    unsigned char command_data[1];
}command_t;

#define GET_DEVICE_STATUS       0x11    //读取节点控制器所控制的设备的参数
#define SET_DEVICE_STATUS       0x12    //设置节点控制器所控制的设备的参数
#define GET_NODE_STATUS         0x13    //读取节点控制器自身参数
#define SET_NODE_STATUS         0x14    //设置节点控制器自身参数

#define ERROR_COMMAND_INVAILED  0x11    //错误的命令码

typedef struct device_ctl_s{
    unsigned char device_id;
    unsigned char device_status;
}device_ctl_t;

unsigned char command_process(package_t *package){
    command_t *command = (command_t *)(package->package_data);

    switch(command->command_id){
        case GET_DEVICE_STATUS:
            package->head.target_id = package->head.source_id;
            send_package(package);
            break;
        case GET_NODE_STATUS:
            package->head.target_id = package->head.source_id;
            send_package(package);
            break;
        case SET_DEVICE_STATUS:
            package->head.target_id = 0xbb;
            send_package(package);
            START_RECV();//数据包处理完成,重新开启接收程序
            break;
        case SET_NODE_STATUS:
            package->head.target_id = 0xcc;
            send_package(package);
            break;
        default:
//          START_RECV();//数据包处理完成,重新开启接收程序
            package->head.target_id = 0xdd;
            send_package(package);
            START_RECV();//数据包处理完成,重新开启接收程序
            return ERROR_COMMAND_INVAILED;
    }

    START_RECV();//数据包处理完成,重新开启接收程序

    return 0;
}

#if 1
void sleep(unsigned int time_out){
    unsigned int time=jiffies;
    unsigned char n=0;
    do{
        ;
    }while(jiffies-time < time_out);
    return;
}

void send_test(){
    unsigned char device_id, device_status;
    package_t *package = w_buf;
    command_t *command = package->package_data;
    device_ctl_t *device_ctl = command->command_data;
    this_node_id = 0x20;

    while(1){
        for(device_id=0; device_id<2; device_id++){
            for(device_status=0; device_status<2; device_status++){
                STOP_RECV();
                memset(package, 0, W_BUF_LEN);
                package->head.target_id = 0x30;
                command->command_id = SET_DEVICE_STATUS;
                device_ctl->device_id=device_id;
                device_ctl->device_status=device_status;
                send_package(package);
                START_RECV();
                sleep(20000);
            }
        }
    }
}

void recv_test(){
    this_node_id = 0x30;
    while(1){
        unsigned char i;
        START_RECV();//数据包处理完成,重新开启接收程序
        while(!recv_over)//等待数据包
            sys_thread();
        for(i=0; i<W_BUF_LEN; i++)
            serial_out(w_buf[i]);
    }
}

#endif

#if 0   //中央控制器
void main(){
    sys_init();

    while(1){
        unsigned char scmd;
        sys_thread();
        if(recv_over){
            unsigned char i;
            for(i=0; i<W_BUF_LEN; i++)
                serial_out(w_buf[i]);
            START_RECV();
        }
        if(RI && wait_serial(&scmd, 1, 0) == 0){//串口命令处理程序
            switch(scmd){
                case 'f':{      //fill w_buf and send
                    unsigned char ret, len;
    
                    STOP_RECV();//停止接收,因为接收与发送是共用缓冲区,运行接收会干扰缓冲区.但目前该行程序暂是多余,因为目前取消了并行收发.
    
                    if(wait_serial(&len, 1, 1000))
                        break;
                    if(wait_serial(w_buf, len, 1000))
                        break;
                    ret = send_package((package_t *)w_buf);
                    serial_out(ret);
    
                    break;
                }
                case 'g':{      //get w_buf
                    unsigned char len = W_BUF_LEN;
                    unsigned char *p = w_buf;
    
                    if(recv_over){
                        do {
                            serial_out(*p);//将数据传给主机
                            p++;
                        }while(--len);
                    }else{
                        serial_out(ERROR_RECV_EMPTY);//目前缓冲区内空,无数据可取
                    }
                    break;
                }
            }
            START_RECV();
        }
    }
}

#else   //节点

void main(){
    sys_init();

    while(1){
        unsigned char ret;
        package_t *package = (package_t*)w_buf;
        while(!recv_over)//等待数据包
            sys_thread();

        //sleep(3000);
        send_package(package);
        START_RECV();//数据包处理完成,重新开启接收程序
        continue;

        ret = recv_package((package_t*)w_buf);//处理接收到的数据包,包括检查数据包的正确性

        if(ret){
            package_t *package = (package_t*)w_buf;
            START_RECV();//数据包处理完成,重新开启接收程序
            package->head.target_id = 0xaa;
            send_package(package);
            START_RECV();//数据包处理完成,重新开启接收程序
        }else{
            ret = command_process((package_t*)w_buf);
        }
    }
}
#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -