利用IO模擬串口對於接收比較復雜,穩定性肯定沒有串口模塊穩定性好,而且要占用一個定時器中斷,對於不允許使用中斷的場合就不能適應,比如高速的無刷控制器,我發明了一種方案可以解決這個問題,除了傳輸速度慢以外,有很多優點,因為越慢越穩定,目前為單主多從,其很容易擴展為類似can那樣的單線多主方式,由於個人原因沒有條件與時間將此方案改的完美,現在將其分享給需要的人
/* ********************************************************************************************************* ********************************************************************************************************* * File : ucos.h * By : Minglie * Date : ********************************************************************************************************* */ #ifndef __Ucos_H #define __Ucos_H #include "HT66F018.h" //announce all the head files #include "Main_Constant.h" void os_init(); void task0(void); #define OSTCBCur 0 #define OSTimeDly(k) {task[OSTCBCur].one.rdy =0; task[OSTCBCur].delay =k-1; } #define OSTimeTick()\ {\ if(task[0].delay ==0) task[0].one.rdy=1;\ else task[0].delay --;\ task0();\ }\ #define config_max_tasks 1 //最大任務個數 #define configTICK_RATE_us 800 //800us 配置心跳周期 #define config_single_wire_task0_mode 0 //單線工作模式,0為主機,1為從機 #define config_com_task0_lengh 8 //配置通信有效位數,只能取2,4,6,8 //引腳配置 #define COM _pc0 #define COM_C _pcc0 //ming_single_wire用到的變量 #pragma rambank0 OS_EXT OSTCB_TypeDef task[config_max_tasks]; //task0的變量 OS_EXT unsigned char task0_dat_cur; OS_EXT unsigned char task0_wait_com_h_count; OS_EXT unsigned char task0_wait_com_l_count; OS_EXT unsigned char task0_tx_buf; OS_EXT unsigned char task0_tx_buf_temp; OS_EXT unsigned char task0_rx_buf; OS_EXT unsigned char task0_rx_buf_temp; OS_EXT unsigned char task0_level_count; OS_EXT bit task0_bit_no_back; OS_EXT bit task0_bit_level_s; OS_EXT bit task0_bit_com_err; #pragma norambank #endif /* ********************************************************************************************************* ********************************************************************************************************* * File : ucos.c * By : Minglie * Date : ********************************************************************************************************* */ #include "Main_Constant.h" #include "ucos.h" void os_init() { //初始化時鍾800us ///////////////////////////////////////////////////////////////// _tm2c0 = 0b01010000; _tm2c1 = 0b11000001; _tm2dl = 0x00; _tm2dh = 0x00; _tm2al = configTICK_RATE_us & 0xff; _tm2ah = configTICK_RATE_us >> 8; _tm2rp = 0x00; _t2on = 1; task0_bit_level_s = 0; task0_dat_cur = 0; task0_bit_no_back = 0; task[0].step = 0; task0_bit_com_err = 0; task[0].one.rdy = 1; //任務就緒 task[0].one.enable = 1; //任務使能 task[0].delay = 0; task0_rx_buf = 0; task0_tx_buf = 0; } #if config_single_wire_task0_mode==0 void task0() { if (task[OSTCBCur].one.rdy) { switch (task[OSTCBCur].step) { case 0: { //初始化發送,並發送起始位1ms COM_C = 0; COM = 0; task0_tx_buf_temp = task0_tx_buf; task0_dat_cur = 0; OSTimeDly(5); task[OSTCBCur].step = 1; break; } case 1: {//拉高延時1ms准備發送數據 COM_C = 1; OSTimeDly(5); task[OSTCBCur].step = 2; break; } case 2: {//發送第0,2,4,6,8(從左數) COM_C = 0; COM = 0; if (task0_tx_buf_temp & 0b10000000) { OSTimeDly(10); } else { OSTimeDly(5); } task0_tx_buf_temp <<= 1; task0_dat_cur++; task[OSTCBCur].step = 3; break; } case 3: {//發送第1,3,5,7,9(從左數) COM_C = 1; if (task0_tx_buf_temp & 0b10000000) { OSTimeDly(10); } else { OSTimeDly(5); } task0_tx_buf_temp <<= 1; task0_dat_cur++; if (task0_dat_cur>config_com_task0_lengh + 1) //task0_dat_cur==10, bit[0:9]發送完 { task0_level_count = 0; task0_dat_cur = 0; task[OSTCBCur].step = 4; } else { task[OSTCBCur].step = 2; } break; } case 4: { ////////////////////////////////////// //開始接收 COM_C = 1; if (COM)//等待對方發送,對齊 { task[OSTCBCur].step = 4; task0_level_count++; // if (task0_level_count>20) //4ms { task0_level_count = 0; task0_wait_com_h_count = 0; task0_wait_com_l_count = 0; task[OSTCBCur].step = 255; //溢出,跳到異常分支 } } else { task0_bit_level_s = 0; task0_rx_buf_temp = 0; task0_dat_cur = 0; task0_level_count = 0; task[OSTCBCur].step = 5; } break; } case 5: { ////////////////////////////////////// COM_C = 1; if (task0_bit_level_s == COM) { task0_level_count++; if (task0_level_count>20) //4ms溢出 { task0_level_count = 0; task0_wait_com_h_count = 0; task0_wait_com_l_count = 0; task[OSTCBCur].step = 255; //溢出,跳到異常分支 } } else { if (task0_dat_cur>0) task0_rx_buf_temp <<= 1; //如果已經收到一些數據,將得到的數據向左移動 task[OSTCBCur].step = 6; } break; } case 6: { ////////////////////////////////////// if (task0_level_count >= 7) task0_rx_buf_temp++; //超過1.4ms認為是1 task0_bit_level_s ^= 1; task0_dat_cur++; if (task0_dat_cur >= config_com_task0_lengh) //task0_dat_cur==8說明[0:7]數據已經接收完畢 { task0_level_count = 0; task[OSTCBCur].step = 7; task0_rx_buf = task0_rx_buf_temp; } else { task0_level_count = 0; task[OSTCBCur].step = 5; //接收下一位數據 } break; } case 7: { ////////////////////////////////////// COM_C = 1; if (COM == 0) //等待bit[8] { task0_level_count++; if (task0_level_count>20) //4ms { task0_level_count = 0; task0_wait_com_h_count = 0; task0_wait_com_l_count = 0; task[OSTCBCur].step = 255; //溢出,跳到異常分支 } } else { COM_C = 1; OSTimeDly(25); //延時5ms,准備下一次通信 task[OSTCBCur].step = 0; task0_bit_no_back = 0; } break; } case 255: { ////////////////////////////////////// //異常分支 COM_C = 1; task0_bit_no_back = 1;//主板不回復 if (COM == 1) { task0_wait_com_l_count = 0; task0_wait_com_h_count++; task[OSTCBCur].step = 255; if (task0_wait_com_h_count>20) //持續高4ms,重新發送 { task[OSTCBCur].step = 0; task0_wait_com_h_count = 0; } } else { //總線被拉低 task0_wait_com_h_count = 0; task0_wait_com_l_count++; if (task0_wait_com_l_count>80)//16ms { task0_bit_com_err = 1; //總線被拉低 task0_wait_com_l_count = 0; } } break; } } } } #else void task0() { if (task[OSTCBCur].one.rdy) { switch (task[OSTCBCur].step) { case 0: { ////初始化分支 COM_C = 1; task0_level_count = 0; task0_wait_com_l_count = 0; task0_wait_com_h_count = 0; task[OSTCBCur].step = 1; break; } case 1: { //等待起始位 COM_C = 1; if (COM == 1) { task[OSTCBCur].step = 1; task0_wait_com_h_count++; if (task0_wait_com_h_count>100)//持續拉高200us*100=20ms { task[OSTCBCur].step = 0; //重新開始接收 } if (task0_wait_com_l_count >= 2)//檢測到大於400us以上低電平 { task0_level_count = 0; task[OSTCBCur].step = 2; } } else { task0_wait_com_l_count++; task[OSTCBCur].step = 1; } break; } case 2: {//開始接收 COM_C = 1; if (COM)//等待對方發送,對齊 { task[OSTCBCur].step = 2; task0_level_count++; // if (task0_level_count>20) //4ms { task0_level_count = 0; task0_wait_com_h_count = 0; task0_wait_com_l_count = 0; task[OSTCBCur].step = 255; //溢出,跳到異常分支 } } else { task0_level_count = 0; task0_bit_level_s = 0; task0_rx_buf_temp = 0; task0_dat_cur = 0; task[OSTCBCur].step = 3; } break; } case 3: { if (task0_bit_level_s == COM) { task0_level_count++; if (task0_level_count>20) //4ms溢出 { task0_level_count = 0; task0_wait_com_h_count = 0; task0_wait_com_l_count = 0; task[OSTCBCur].step = 255; //溢出,跳到異常分支 } } else { //task0_dat_cur>0 ,說明已經得到至少1bit數據 if (task0_dat_cur>0) task0_rx_buf_temp <<= 1; //將得到的數據向左移動 task[OSTCBCur].step = 4; } break; } case 4: { if (task0_level_count >= 7) task0_rx_buf_temp++; //超過1.4ms認為是1 task0_bit_level_s ^= 1; task0_dat_cur++; if (task0_dat_cur >= config_com_task0_lengh) //task0_dat_cur==8說明[0:7]數據已經接收完畢 { task0_level_count = 0; task[OSTCBCur].step = 5; task0_rx_buf = task0_rx_buf_temp; } else { task0_level_count = 0; task[OSTCBCur].step = 3; //接收下一位數據 } break; } case 5: { COM_C = 1; if (COM == 0) //等待bit[8] { task0_level_count++; if (task0_level_count>20) //4ms { task0_level_count = 0; task0_wait_com_h_count = 0; task0_wait_com_l_count = 0; task[OSTCBCur].step = 255; //溢出,跳到異常分支 } } else { COM_C = 1; OSTimeDly(10); //延時2ms,准備發送 //初始化發送 task0_tx_buf_temp = task0_tx_buf; task0_dat_cur = 0; task[OSTCBCur].step = 6; } break; } case 6: {//發送第0,2,4,6,8(從左數) COM_C = 0; COM = 0; if (task0_tx_buf_temp & 0b10000000) { OSTimeDly(10); } else { OSTimeDly(5); } task0_tx_buf_temp <<= 1; task0_dat_cur++; task[OSTCBCur].step = 7; break; } case 7: {//發送第1,3,5,7,9(從左數) COM_C = 1; if (task0_tx_buf_temp & 0b10000000) { OSTimeDly(10); } else { OSTimeDly(5); } task0_tx_buf_temp <<= 1; task0_dat_cur++; if (task0_dat_cur>config_com_task0_lengh + 1) //task0_dat_cur==10, bit[0:9]發送完 { task0_level_count = 0; task0_dat_cur = 0; COM_C = 1; OSTimeDly(5);//延時1ms,准備下一次接收 task[OSTCBCur].step = 0; } else { task[OSTCBCur].step = 6; } break; } case 255: { //異常分支 COM_C = 1; task0_rx_buf = 0; if (COM == 1) { task0_wait_com_l_count = 0; task0_wait_com_h_count++; task[OSTCBCur].step = 255; if (task0_wait_com_h_count>20) //持續高4ms,重新接收 { task[OSTCBCur].step = 0; task0_wait_com_h_count = 0; } } else { task0_wait_com_h_count = 0; task0_wait_com_l_count++; if (task0_wait_com_l_count>80)//16ms { task0_bit_com_err = 1; //總線被拉低 task0_wait_com_l_count = 0; } } break; } } } } #endif
對於使用只需引入這兩個文件周期性的調用 宏 OSTimeTick()即可實現雙向通信,主機從機是一樣的代碼通過宏config_single_wire_task0_mode 加以區別,這種方式對於時間並不需要很精准,比如你1ms調用一次,突然800us調一次,或1200us一次調用一次,並不會影響通信的正確率,但是你連續的大偏差肯定會出問題,只需保證調用周期偏差可以在20%以內即可,對於將其改進為多主異步就不需要周期調用了