stm32曼彻斯特编码一种自研的解码方法实现

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 Module\r\n");
                
    RFIDTim_init();//定时器配置
    
    RFID_Exti_Init();//IO初始化及中断配置

    DEBUG("finish init EM4095 RFID Module\r\n");

}

 中断处理函数

// 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("\r\n min: %d max: %d ; |舍弃 ! | \r\n",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;
}
 

  • 4
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32一种微控制器芯片系列,具有强大的处理能力和广泛的应用领域。曼彻斯特编码一种数字信号编码技术,常用于数据传输和通信领域。 曼彻斯特编码使用两个互补的信号来表示数字逻辑1和0。在STM32中,可以使用曼彻斯特编码来提高数据传输的可靠性和抗干扰性。曼彻斯特编码的基本原理是将数据信号划分为一系列等长的时间窗口,通过对各窗口内信号电平的变化来表示数据。具体而言,逻辑1由高电平到低电平的变化表示,逻辑0则由低电平到高电平的变化表示。 STM32中的曼彻斯特编码可以通过内置的硬件模块来实现。通过设置相关寄存器和配置引脚的工作方式,可以将要发送的数据转换为曼彻斯特编码的信号,并通过相应的引脚发送出去。在接收端,通过相同的硬件模块和配置,可以将接收到的曼彻斯特编码信号还原为原始的数据。这种硬件实现方式可以提高数据传输的效率,并减少对CPU处理的负担。 曼彻斯特编码具有传输速率稳定、传输距离较长等特点,广泛应用于通信领域,如以太网、无线通信、红外遥控等。在STM32的应用中,曼彻斯特编码可以用于串行通信接口,如USART、SPI、I2C等。通过使用曼彻斯特编码,可以提高通信的可靠性和稳定性,确保数据的准确传输。 综上所述,STM32通过内置的硬件模块实现曼彻斯特编码技术,可以用于提高数据传输的可靠性和抗干扰性。在不同的应用场景下,可以选择合适的通信接口和配置方式来实现曼彻斯特编码的数据传输。 ### 回答2: STM32曼彻斯特编码一种数据传输编码方式,常用于串行通信中的数据传输。它将每个数据位转换为两个时钟周期,并通过时钟的上升沿或下降沿来表示数据位的取值。在STM32中,曼彻斯特编码是通过硬件电路实现的。 曼彻斯特编码的基本原理是通过改变信号的电平或电平的跳变来表示数据的0或1。具体而言,bit0被编码为0到1的跳变,而bit1被编码为1到0的跳变。通过这种编码方式,可以解决在数据传输过程中的时钟同步问题,并提高数据传输的可靠性。 在STM32中,曼彻斯特编码可以通过使用USART(通用同步异步收发器)或UART(通用异步收发器)的硬件功能实现。通过配置硬件寄存器,可以设置通信波特率、数据位数、停止位数等参数,以满足不同通信需求。 曼彻斯特编码的一个重要应用是在以太网通信中,它可以有效地识别出数据位的边界,避免数据传输过程中的位错误。此外,在无线通信和电力线通信中也广泛采用曼彻斯特编码。 总而言之,STM32曼彻斯特编码一种常用的数据传输编码方式,通过改变信号的电平或电平的跳变来表示数据的0或1,并通过硬件电路实现。它具有解决时钟同步问题、提高数据传输可靠性的优势,并在各种通信领域得到广泛应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值