参照下面文章,单线通讯—SIF通讯协议(一线通)案例二 作者Geek YANG,程序中有少许错误,移植过来后,有修改,比如数据的时间长度,校验方式,接收收据的处理等,最后成功实现。
注释有些没改过来。。
/*******************************************************************************
*@时 间 : 2022-2-22
*@摘 要 : 主程序文件
*@芯 片 : GD32F103CBT6
* -------------
*******************************************************************************/
/*================================= Demo说明 ===================================
定时器 + 一个GPIO口进行通讯数据读取
==============================================================================*/
/* 包含的头文件 ---------------------------------------------------------------*/
#include <gd32f10x.h>
#include <gd32f103e_eval.h>
/* 宏定义 ---------------------------------------------------------------------*/
#define DATA_REV_PIN gpio_input_bit_get(GPIOB,BIT(9)) //定义数据接收引脚(根据实际项目进行更改)
#define LOW 0 //低电平
#define HIGH 1 //高电平
#define SYNC_L_TIME_NUM 1100 //同步信号低电平时间:50ms = 50000us / 50us = 1000
#define SYNC_H_TIME_NUM_MIN 8 //同步信号高电平最小时间:500-100us = 400us / 50us = 8
#define SYNC_H_TIME_NUM_MAX 12 //同步信号高电平最大时间:500+100us = 600us / 50us = 12
#define SHORT_TIME_NUM_MIN 9 //一个逻辑周期中短的时间最小值:500-50us = 450us / 50us = 9
#define SHORT_TIME_NUM_MAX 11 //一个逻辑周期中短的时间最大值:500+50us = 550us / 50us = 11
#define LONG_TIME_NUM_MIN 18 //一个逻辑周期中长的时间最小值:1ms-100us = 900us / 50us = 18
#define LONG_TIME_NUM_MAX 22 //一个逻辑周期中长的时间最大值:1ms+100us = 1100us / 50us = 22
#define LOGIC_CYCLE_NUM_MIN 26 //一个逻辑周期最小时间:1.5ms-200us = 1300us / 50us = 26
#define LOGIC_CYCLE_NUM_MAX 34 //一个逻辑周期最大时间:1.5ms+200us = 1700us / 50us = 34
#define HALF_LOGIC_CYCLE_MIN 13 //一个逻辑周期的1/2最小时间:750-100us = 650us / 50us = 13
#define HALF_LOGIC_CYCLE_MAX 17 //一个逻辑周期的1/2最大时间:750+100us = 850us / 50us = 17
#define END_SIGNAL_TIME_NUM 100 //结束信号电平时间:5ms低电平 + Nms高电平,实际检测5ms低电平就行,一帧数据发送完成后检测5ms低电平就代表完成了,不发数据的时候上拉电阻拉高了
#define REV_BIT_NUM 8 //接收的bit位个数,看是按字节接收还是按字接收,1字节=8bit,1字=2字节=16bit
#define REV_DATA_NUM 12 //接收的数据个数
/* 类型定义 -------------------------------------------------------------------*/
typedef enum
{
INITIAL_STATE=0, //初始状态,等待接收同步信号
SYNC_L_STATE=1, //接收同步低电平信号状态
SYNC_H_STATE=2, //接收同步高电平信号状态
DATA_REV_STATE=3, //读取数据码电平状态
END_SIGNAL_STATE=4, //接收结束电平信号状态
RESTART_REV_STATE=5 //接收过程出错重新接收状态
}REV_STATE_e; //接收数据状态枚举
/* 变量定义 -------------------------------------------------------------------*/
unsigned char receive_state=0; //接收数据状态
unsigned char receive_bit_num=0; //接收的bit位个数
unsigned char receive_data_num=0; //接收的数据个数
//接收数据缓存数组-用一个数组来缓存数据,51个数据字节
unsigned char receive_data_buf[REV_DATA_NUM]={0};
unsigned char receive_data[REV_DATA_NUM] = {0};
unsigned int H_L_Level_time_cnt=0; //高低电平时间计数
uint8_t start_H_L_Level_timming_flag=0; //开始高低电平计时标记
uint8_t has_read_bit = 0; //1-已经读取一个bit位
uint8_t check_OK = 0; //1-校验和正确,0-校验和失败
uint8_t read_success=0; //一帧数据是否读取成功,0-不成功,1-成功
uint8_t Pin_Old = 0;
uint8_t Pin_New = 0;
uint8_t Pin_Change_Flag = 0;
uint8_t BitFinish_Flag = 0;
/* 函数声明 -------------------------------------------------------------------*/
void GPIO_Init(void); //GPIO初始化函数
void Timer0_Init(void); //定时器0初始化函数
void Receive_Data_Handle(void); //接收数据处理
void Check_Sum_Handle(void); //校验和处理
/* 函数定义 -------------------------------------------------------------------*/
/*******************************************************************************
*函数名称 : main
*函数功能 : 主函数入口
*输入参数 : void
*输出返回 : void
*******************************************************************************/
void SIF_Handle(void)
{
if (read_success == 1) //如果成功读取一帧数据
{
//一帧数据接收成功后先根据协议要求进行校验和,验证数据的正确性
Check_Sum_Handle();
//如果数据正确,根据接收的数据进行分析获取需要的内容
if (check_OK)
{
memcpy(receive_data, receive_data_buf, REV_DATA_NUM);
}
read_success = 0; //读取一帧数据清0
}
}
/*******************************************************************************
*函数名称 : Timer0_isr
*函数功能 : 定时器0中断处理函数
*输入参数 : void
*输出返回 : void
*******************************************************************************/
void TIMER1_IRQHandler(void)
{
if(SET == timer_interrupt_flag_get(TIMER1, TIMER_INT_CH0)){
/* clear channel 0 interrupt bit */
timer_interrupt_flag_clear(TIMER1, TIMER_INT_CH0);
Pin_New = DATA_REV_PIN;
if (start_H_L_Level_timming_flag==1)
{
H_L_Level_time_cnt++; //高低电平维持时间计数变量
Pin_Change_Flag = 0;
BitFinish_Flag = 0;
if(Pin_New != Pin_Old)
{
Pin_Change_Flag = 1;
if(0 == Pin_New)
{BitFinish_Flag = 1;}
}
Pin_Old = Pin_New;
}
Receive_Data_Handle(); //接收数据处理,波特率自适应
gd_eval_led_toggle(LED2);
}
}
/*******************************************************************************
*函数名称 : Receive_Data_Handle
*函数功能 : 接收数据处理
*输入参数 : void
*输出返回 : void
*******************************************************************************/
void Receive_Data_Handle(void)
{
switch (receive_state) //检测当前接收数据状态
{
case INITIAL_STATE: //初始状态,未接收到同步信息,进行同步判断
if (DATA_REV_PIN == LOW) //判断接收引脚的电平状态,当读到低电平时,开始计时
{
receive_bit_num = 0; //重置bit位计数器
receive_data_num = 0; //重置接收数据个数
H_L_Level_time_cnt = 0; //高低电平计时变量清0
start_H_L_Level_timming_flag = 1; //开始高低电平计时
receive_state = SYNC_L_STATE; //进入读取同步低电平信号状态
memset(receive_data_buf, 0 ,REV_DATA_NUM);
}
break;
case SYNC_L_STATE: //在读取同步低电平信号期间
if (DATA_REV_PIN == HIGH) //同步信号低电平检测期间读到高电平
{
if (H_L_Level_time_cnt >= SYNC_L_TIME_NUM)//如果同步信号低电平时间>=SYNC_L_TIME_NUM
{ //同步信号低电平时间要>=10ms
H_L_Level_time_cnt = 0; //高低电平计时变量清0
receive_state = SYNC_H_STATE; //进入读取同步信号高电平状态
}
else
{
receive_state = RESTART_REV_STATE; //进入重新接收状态
}
}
break;
case SYNC_H_STATE: //在读取同步信号高电平期间
if (DATA_REV_PIN == LOW) //同步信号高电平检测期间读到低电平
{
//判断同步信号高电平时间是否在1ms±100us之间
if (H_L_Level_time_cnt >= SYNC_H_TIME_NUM_MIN && H_L_Level_time_cnt <= SYNC_H_TIME_NUM_MAX)
{
H_L_Level_time_cnt = 0; //高低电平计时变量清0
receive_state = DATA_REV_STATE; //进入读取数据状态
}
else
{
receive_state = RESTART_REV_STATE; //进入重新接收状态
}
}
else //如果在同步信号高电平检测期间,时间超过2ms±200us,认为超时
{
//判断时间是否超时 2ms±200us
if (H_L_Level_time_cnt >= LOGIC_CYCLE_NUM_MAX)
{
receive_state = RESTART_REV_STATE; //进入重新接收状态
}
}
break;
case DATA_REV_STATE: //在读取数据码电平期间
if ((has_read_bit==0) && (H_L_Level_time_cnt >= HALF_LOGIC_CYCLE_MIN && H_L_Level_time_cnt <= HALF_LOGIC_CYCLE_MAX))
{
receive_data_buf[receive_data_num] |= DATA_REV_PIN;
has_read_bit = 1;
}
//如果已经读取一个bit位,且时间计数已经>=2ms±200us,说明一个逻辑周期过去了
if ((has_read_bit==1) && (H_L_Level_time_cnt >= LOGIC_CYCLE_NUM_MIN && H_L_Level_time_cnt <= LOGIC_CYCLE_NUM_MAX))
//if ((has_read_bit==1) && (1 == BitFinish_Flag))
{
H_L_Level_time_cnt = 0; //高低电平计时变量清0
has_read_bit = 0; //清0,读取下一个bit位
receive_bit_num++; //接收的bit数++
if (receive_bit_num == REV_BIT_NUM) //如果一个字节8个bit位接收完成
{
//receive_data[receive_data_num] = receive_data_buf[receive_data_num];
receive_data_num++; //接收的数据个数++
receive_bit_num = 0; //接收bit位个数清0重新接收
if (receive_data_num == REV_DATA_NUM) //如果数据采集完毕
{
receive_state = END_SIGNAL_STATE; //进入接收结束低电平信号状态
}
}
else //如果一个字节8个bit位还没有接收完成
{
//将接收数据缓存左移一位,数据从低bit位开始接收
receive_data_buf[receive_data_num] = receive_data_buf[receive_data_num] >> 1;
}
}
break;
case END_SIGNAL_STATE: //在接收结束信号低电平期间
if (DATA_REV_PIN == LOW)
{
if (H_L_Level_time_cnt >= END_SIGNAL_TIME_NUM) //如果读到低电平时间>=5ms
{
read_success = 1; //一帧数据读取成功
SIF_Handle();
start_H_L_Level_timming_flag = 0; //停止高低电平计时
H_L_Level_time_cnt = 0; //定时器计数值清0
receive_state = INITIAL_STATE; //接收状态清0
}
}
else //结束信号低电平检测期间一直为低
{
//if (H_L_Level_time_cnt >= SYNC_L_TIME_NUM) //如果读到低电平时间>=10ms,认为超时
{ //一帧数据发送完成后需要间隔50ms才发送第二帧数据,期间肯定会被拉高
receive_state = RESTART_REV_STATE; //进入重新接收状态
}
}
break;
case RESTART_REV_STATE: //重新接收数据状态
start_H_L_Level_timming_flag = 0; //停止高低电平计时
H_L_Level_time_cnt = 0; //定时器计数值清0
receive_state = INITIAL_STATE; //接收状态清0
break;
}
}
/*******************************************************************************
*函数名称 : Check_Sum_Handle
*函数功能 : 校验和处理
*输入参数 : void
*输出返回 : void
*******************************************************************************/
void Check_Sum_Handle(void)
{
unsigned char i = 0, checkByte = 0;
unsigned long checkXor = 0;
for ( i = 0; i < (REV_DATA_NUM ); i++)
{
checkXor = checkXor ^ receive_data_buf[i];
}
checkByte = (unsigned char)checkXor;
if (checkByte == receive_data_buf[REV_DATA_NUM-1]) //校验和正确
{
check_OK = 1; //标记校验成功
}
else
{
check_OK = 0; //标记校验失败
}
}
uint8_t * pGetSIFData(void)
{
return receive_data;
}
最后版本的源文件附上:SIF.c
接收的数据,用串口发送出来,如下
完。