1.什么是曼彻斯特编码?
首先了解下什么是曼彻斯特编码,任何编码都是为了表示数据,在玩单片机都知道单片机数据最基础就是二进制数据1和0,曼彻斯特编码就是通过高低电平的变化来表示1和0,当电平由低变高时表示数据1,由高变低时为数据0,如下图:
2.数据会出错?引入时钟
1和0确定好,那么就出现了一个问题,如果数据是101会怎样?如下图:
按照我们刚说的 电平由低变高时表示数据1,由高变低时为数据0,上图的高低变化是怎么样的?低->高->低->高,数据是不是就会被误判为 11 ,为了解决这个问题,所以我们必须要限定高低电平持续的时间多久才能确切知道是 低->高->高->低->低->高 (101) ,还是 低->高->低->高(11),所以就引入一个时钟线来提供固定频率,以确定高低时间持续多少个时钟周期。
至此为什么曼彻斯特编码需要一根时钟线和一根数据线 ,大家应该彻底理解了。
3.实验发现问题,确定曼彻斯特编码头
那么在实验时又发现问题,因为曼彻斯特基本都用于RFID领域,线圈受到地磁场或空气中各种电磁场影响很多数据输出的端子都很不稳定,如果不定义一个数据头很容易误读很多数据,引起资源浪费,所以发明者给曼彻斯特编码设定了一个曼彻斯特编码头 9个 1 。
至此什么是曼彻斯特编码我们就完全理解了。
4.实现曼彻斯特解码
了解了原理那么读数据就变的简单了,各有各的想法,我这里主要提供一种思路,可以不借助时钟线照样读出曼彻斯特数据。采用一个中断一个定时器 通过平均时间对比法来确定数据线上的数据。思路就是记录每次高低电平持续时间与一个时钟周期的时间对比,确定数据的1和0。
具体实现:用中断来侦测数据线高低电平变化,每次高低变化时触发中断,此时开始定时器计时,等下次中断再来时记录下定时器时间,这样我们就可以获取一段数据过来时所有的高低电平持续时间,获取到这些时间后取平均值,就大致推算出了一个时钟周期大概的时间,拿每一个数据去跟这个时间对比,找到第一个连续18个时间都大致等于这个时间平均值的地方,说明是9个1到来了,此后的数据 每一位都与 这个时间平均值比较 如果是 大概等于这个时间 那就说明 这段高/低电平持续了一个时钟周期,如果 大概等于 2个 时间的平均值 , 那就说明 这段高/低电平持续了2个时钟周期,那么再依据IO中断是高低电平轮流触发,通过这段时间的位置奇偶数,就可确定数据线高低电平跟随时钟变化情况,用1和0表示高低电平,记录下来,再每2位判断是1->0 还是 0->1确定数据是0还是1,至此就获取到了我们要的数据。
代码如下:
//定时器配置
void RFIDTim_init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseSt;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_DeInit(RFID_TIM);
TIM_TimeBaseSt.TIM_Prescaler = 72-1; //
TIM_TimeBaseSt.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseSt.TIM_Period = 1000;
TIM_TimeBaseSt.TIM_ClockDivision =TIM_CKD_DIV1;
TIM_TimeBaseInit(RFID_TIM, &TIM_TimeBaseSt);
TIM_Cmd(RFID_TIM, ENABLE);
DEBUG("time init ok n");
}
//IO及中断配置
void RFID_Exti_Init(void){
EXTI_InitTypeDef EXTI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable GPIOA clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* Enable AFIO clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/* Configure PA.00 pin as input floating */
GPIO_InitStructure.GPIO_Pin = OUT_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(OUT_PORT, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource7);//将PA7挂在中断源上
/* Configure EXTI0 line */
EXTI_InitStructure.EXTI_Line = EXTI_Line7;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
EXTI_ClearITPendingBit(EXTI_Line7);
/* Enable and set EXTI0 Interrupt to the lowest priority */
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//RFID初始化
void RFIDInit(void)
{
DEBUG("Start Init EM4095 RFID Modulern");
RFIDTim_init();//定时器配置
RFID_Exti_Init();//IO初始化及中断配置
DEBUG("finish init EM4095 RFID Modulern");
}
中断处理函数
// Interrupt bei Flankenwechsel
void EXTI9_5_IRQHandler(void)
{
static u8 N = 0;
if(EXTI_GetITStatus(EXTI_Line7) != RESET)
{
if(gFlag == 0x00)
{
TT_Buffer[N]= TIM_GetCounter(RFID_TIM); //数组记录计时器计时时间
TT_voltage[N]=GPIO_ReadInputDataBit(OUT_PORT,OUT_PIN);//数组保存此时IO电平
TIM_SetCounter(RFID_TIM, 0);//计时器清0
N++;
if(N== 1)//cym
{
gFlag = 0xFF;
}
}
EXTI_ClearITPendingBit(EXTI_Line7);
}
}
//数据解析
unsigned char Decode(void)
{
u16 min,max,avg,i,n;
min = 0xFF;max = 0xFF;avg = 0xFF;i = 0xFF;n = 0xFF;
//-------------------- STEP1: 找出 [平均值]
for(i=1; i<256; i++) //---- 从1开始! 0字节是不可靠数据
{
if(TT_Buffer[i]<min)
{
min = TT_Buffer[i];
}
if(TT_Buffer[i]>max)
{
max = TT_Buffer[i];
}
}
//数据过滤
if(min<100||max>1000)
{
//DEBUG("rn min: %d max: %d ; |舍弃 ! | rn",min,max);
return 0;
}
avg=((min+max)/2);//-----平均值
n = 0;
//-------------------- STEP2: 提取原始数据
for(i=1; i<256; i++) //---- 必须从1开始! 0字节是不可靠数据
{
if (TT_Buffer[i]<avg )//(abs((int)TT_Buffer[i] - 245)<=70)
{
if (TT_voltage[i]==1)
Bin_Buffer[n++]=0;
else
Bin_Buffer[n++]=1;
}
else if (TT_Buffer[i]>avg )//(abs((int)TT_Buffer[i] - 485)<=70)
{
if (TT_voltage[i]==1)
{
Bin_Buffer[n++]=0;
Bin_Buffer[n++]=0;
}
else
{
Bin_Buffer[n++]=1;
Bin_Buffer[n++]=1;
}
}
}
//-------------------- STEP3: 查找RFID头标志(9个1)
i = n-128; //------- 有效起始点!
while(i--)
{
if(FindHeader(i))
{
if(FindID(i))
{
return 1;
}
}
}
return 0;
}
/*=================== 查找RFID 头标志 9个1
//--- 匹配返回:1
//--- 无效返回:0*/
u8 FindHeader(u16 index)
{
u8 n;
if((Bin_Buffer[index]==0)&&(Bin_Buffer[index+1]==1))//cym 1/0
{
index++;
index++;
}
else
{
return (0);
}
for(n=0; n<9; n++)
{
if((Bin_Buffer[index]==1)&&(Bin_Buffer[index+1]==0))//cym 0/1
{
index = index+2;
}
else
{
return (0);
}
}
return (1);
}
将头后的数据解析为实际的卡号数据。
u8 FindID(u16 i)
{
u8 n;
u8 k;
u8 sum;
//-------------------- STEP1: 提取RFID有效数据
if(i)
{
for(n=0; n<11; n++)RFID[n] = 0x00; //------ Buffer清零
i = i+20; //--- 有效数据流
for(k=0; k<11; k++)
{
for(n=0; n<5; n++)
{
RFID[k] = RFID[k]<<1;
if((Bin_Buffer[i]==1)&&(Bin_Buffer[i+1]==0))//cym 0/1
{
RFID[k] |= 0x01;
}
i += 2;
}
}
}
//---------------------------- STEP2: 校对数据
//---------------------- X 轴校验
for(k=0; k<10; k++)
{
sum = 0;
if(RFID[k]&0x01)sum++;
if(RFID[k]&0x02)sum++;
if(RFID[k]&0x04)sum++;
if(RFID[k]&0x08)sum++;
if(RFID[k]&0x10)sum++;
if(sum%2) //--- 偶校验出错!
{
// MessageBox("X 轴校验出错!");
return 0;
}
}
//------------------- Y 轴校验
sum = 0;
for(k=0; k<11; k++)
{
sum ^= RFID[k];
}
if(sum&0x1E) //--- 偶校验出错!
{
//MessageBox("Y 轴校验出错!");
return 0;
}
//------------------ STEP3: 获取RFID卡号(4个字节32位)
for(k=0; k<10; k++)
{
RFID[k] = RFID[k]>>1; //---去掉校验值
}
Vendor = 0;
CardIDH = 0;
CardIDL = 0;
k = RFID[0]<<4;
Vendor = k|RFID[1]; //--- 卡版本或供应商信息
k = RFID[2]<<4;
k |= RFID[3];
CardIDH |= k<<8;
k = RFID[4]<<4;
k |= RFID[5];
CardIDH |= k;
k = RFID[6]<<4;
k |= RFID[7];
CardIDL |= k<<8;
k = RFID[8]<<4;
k |= RFID[9];
CardIDL |= k;
//------------------ STEP4: 显示解码结果
return 1;
}
最后
以上就是无聊星月最近收集整理的关于stm32曼彻斯特编码一种自研的解码方法实现的全部内容,更多相关stm32曼彻斯特编码一种自研内容请搜索靠谱客的其他文章。
发表评论 取消回复