📄 test.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 + -