在低端單片機之間的單線IO通信


    利用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%以內即可,對於將其改進為多主異步就不需要周期調用了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM