EBIKE-FreeRTOS/Source/SIF.c

237 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "SIF.h"
#include "common.h"
#define DATA_REV_PIN gpio_get(SIF_REV_PIN)
#ifdef _SIF_DEBUG_
char log_str[128] = { 0 };
#endif
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; //接收的数据个数
unsigned char sif_receive_data_buf[REV_DATA_NUM] = { 0 }; //接收数据缓存数组如果一帧数据有多个数据打开注释
unsigned char sif_receive_data[REV_DATA_NUM] = { 0 };
unsigned int H_L_Level_time_cnt = 0; //高低电平时间计数
unsigned int Tosc = TOSC; //波形时基单元一般带波特率自适应的不会说明高低电平的时间会用一个Tosc时基描述
//如上面的波形图,要求 32Tosc = 0.5ms = 500us
//所以一个Tosc = 500us/32 ≈ 15us而定时器0单次定时时间为5us所以实际一个Tosc = 15us/5us = 3 次
//可以理解为 5us 是人为设置的一个定时器单次定时时间再这个定时时间的基础上又产生了一个实际时基Tosc用在波形上波形基于这个Tosc时基单元
//可以动态的调整高低电平的时间只要Tosc改变992Tosc和32Tosc以及64Tosc对应的时间也会随之改变然后我们反过来思考再不知道波特率的情况下
//去读取同步信号高电平的时间将读到的时间计数H_L_Level_time_cnt * 15us是高电平的真实维持时间 = 32 * Tosc * 5us = SHORT_TIME_NUM * Tosc * 5us
//Tosc = H_L_Level_time_cnt / SHORT_TIME_NUM
//在本案例中,一帧数据 = 992Tosc+32Tosc+(64+32)*8*12Tosc = 10240*Tosc 次
//1秒钟 = 1000000us单次定时 5us则1s / 5us = 200000 次
//则1秒钟可以接收 200000 / (10240 * Tosc) = 200000/10240/Tosc = 19/Tosc 帧数据
uint8_t start_H_L_Level_timming_flag = 0; //开始高低电平计时标记
uint8_t has_read_bit = 0; //1-已经读取一个bit位
uint8_t read_success = 0; //一帧数据是否读取成功0-不成功1-成功
uint8_t is_end_bit = 0; // 结束帧判定 0-未结束,1-结束标志
void GPIO_SIF_Init(void)
{
gpio_init(SIF_REV_PIN);
gpio_set_dir(SIF_REV_PIN, GPIO_OUT);
}
void TIMER_SIF_IRQHandler(void)
{
if (start_H_L_Level_timming_flag == 1) {
H_L_Level_time_cnt++; //高低电平维持时间计数变量
}
Receive_SIF_Data_Handle(); //接收数据处理,波特率自适应
}
void Receive_SIF_Data_Handle(void)
{
switch (receive_state) //检测当前接收数据状态
{
case INITIAL_STATE: //初始状态,未接收到同步信息,进行同步判断
if (DATA_REV_PIN == LOW) //判断接收引脚的电平状态,当读到低电平时,开始计时
{
receive_bit_num = REV_BIT_NUM; //重置bit位计数器
receive_data_num = 0; //重置接收数据个数
H_L_Level_time_cnt = 0; //高低电平计时变量清0
read_success = 0; //结束位置低电平判定清零
start_H_L_Level_timming_flag = 1; //开始高低电平计时
is_end_bit = 0;
receive_state = SYNC_L_STATE; //进入读取同步低电平信号状态
memset(sif_receive_data_buf, 0, 16);
}
break;
case SYNC_L_STATE: //在读取同步低电平信号期间
if (H_L_Level_time_cnt > SYNC_TIME_NUM * Tosc) //如果低电平时间 > SYNC_TIME_NUM*Tosc=992*3*5us
{ //同步状态空闲时间大于15ms
if (DATA_REV_PIN == HIGH) //判断接收引脚的电平状态,当读到高电平时
{
H_L_Level_time_cnt = 0; //高低电平计时变量清0
receive_state = SYNC_H_STATE; //进入读取同步信号高电平状态
}
} else {
if (DATA_REV_PIN == HIGH) //同步信号低电平检测期间读到高电平重新计时
{
receive_state = RESTART_REV_STATE; //进入重新接收状态
}
}
break;
case SYNC_H_STATE: //在读取同步高电平信号期间
if (H_L_Level_time_cnt >= LOGIC_CYCLE_NUM * Tosc) //如果高电平时间超过了32+64=96个Tosc则认为超时
{
receive_state = RESTART_REV_STATE; //进入重新接收状态
} else {
if (DATA_REV_PIN == LOW) //同步信号高电平检测期间读到低电平
{
//在同步信号高电平检测期间读到低电平可能有如下状态:
//1、高电平时间短不满32Tosc
//2、高电平时间正好=32Tosc
//3、高电平时间长超过32Tosc
//不管何种状态,都要 调整 Tosc 的值达到波特率自适应
//H_L_Level_time_cnt * 5us 要求是 SHORT_TIME_NUM * Tosc * 5us
//即 H_L_Level_time_cnt = SHORT_TIME_NUM * Tosc
Tosc = H_L_Level_time_cnt / SHORT_TIME_NUM; //调整 Tosc 的值
H_L_Level_time_cnt = 0; //高低电平计时变量清0
receive_state = DATA_REV_STATE; //进入读取数据码低电平状态
}
}
break;
case DATA_REV_STATE: //在读取数据码电平期间
//逻辑"0"为 64Tosc低电平 + 32Tosc高电平
//逻辑"1"为 32Tosc低电平 + 64Tosc高电平
//不管是逻辑"0"还是逻辑"1"周期一样都是32Tosc + 64Tosc = 96Tosc
//可以取中间时间点进行判断96Tosc / 2 = 48Tosc当计数>=48Tosc时读取引脚电平
//如果还没有读取一个bit位且时间计数已经>=48Tosc
if ((has_read_bit == 0) && (H_L_Level_time_cnt >= (HALF_LOGIC_CYCLE * Tosc))) {
sif_receive_data_buf[receive_data_num] |= DATA_REV_PIN;
has_read_bit = 1;
}
//如果已经读取一个bit位且时间计数已经>=96Tosc说明一个逻辑周期过去了
if ((has_read_bit == 1) && (H_L_Level_time_cnt >= (LOGIC_CYCLE_NUM * Tosc))) {
H_L_Level_time_cnt = 0; //高低电平计时变量清0
has_read_bit = 0; //清0读取下一个bit位
receive_bit_num--; //接收的bit数--
if (receive_bit_num == 0) //如果一个字节8个bit位接收完成
{
receive_data_num++; //接收的数据个数++
receive_bit_num = REV_BIT_NUM; //重置接收bit位个数
if (receive_data_num >= REV_DATA_NUM) //如果数据采集完毕 超出了最大值
{
start_H_L_Level_timming_flag = 0; //停止高低电平计时
H_L_Level_time_cnt = 0; //定时器计数值清0
receive_state = INITIAL_STATE; //接收状态清0
}
} else //如果一个字节8个bit位还没有接收完成
{
//将接收数据缓存左移一位数据从高bit位开始接收
sif_receive_data_buf[receive_data_num] = sif_receive_data_buf[receive_data_num] << 1;
}
}
// 记录 结束标志
if (H_L_Level_time_cnt == (END_SIGNAL_FLAG_NUM * Tosc) && (DATA_REV_PIN == LOW)) {
is_end_bit = 1;
has_read_bit = 0;
read_success = 1; //一帧数据读取成功
#ifdef _SIF_DEBUG_
sprintf(log_str, "rn:%d,%s.", receive_data_num, sif_receive_data_buf);
#endif
Check_Sum_Handle();
start_H_L_Level_timming_flag = 0; //停止高低电平计时
H_L_Level_time_cnt = 0; //定时器计数值清0
receive_state = INITIAL_STATE; //接收状态清0
}
break;
case END_SIGNAL_STATE: //在接收结束信号低电平期间
if (DATA_REV_PIN == LOW) {
if (H_L_Level_time_cnt >= END_SIGNAL_TIME_NUM * Tosc) //如果读到低电平时间>=5ms
{
read_success = 1; //一帧数据读取成功
Check_Sum_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
is_end_bit = 0;
receive_state = INITIAL_STATE; //接收状态清0
break;
}
}
unsigned char *pGetSIFData(void) //获取SIF数据
{
return sif_receive_data;
}
#ifdef _SIF_DEBUG_
char *pGetLogStr(void) //获取SIF数据
{
return log_str;
}
#endif
void Check_Sum_Handle()
{
if (read_success == 1) //如果成功读取一帧数据
{
//一帧数据接收成功后先根据协议要求进行校验和,验证数据的正确性
//如果数据正确,根据接收的数据进行分析获取需要的内容
//if (check_OK)
{
memset(sif_receive_data, 0, REV_DATA_NUM);
memcpy(sif_receive_data, sif_receive_data_buf, REV_DATA_NUM);
memset(sif_receive_data_buf, 0, REV_DATA_NUM);
}
read_success = 0; //读取一帧数据清0
}
}
void SIF(void *p)
{
(void)p;
GPIO_SIF_Init();
while (1)
{
char *SIF_DATA = (char *)pGetSIFData();
printf("%s", SIF_DATA);
vTaskDelay(pdMS_TO_TICKS(3000)); // 非阻塞延时
}
return ;
}