在低端单片机之间的单线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