单片机私有通信协议 密码锁
曾经遇到一个案子,需要用到8位单片机做密码锁,主mcu只有与8位单片机完成交互(数据密钥传输)才可以正常使用,案子虽然完成了但是至今我都没有理解到底密码是多少,写案子总结的时候完全是通过示波器抓取通信波形来表达的。
见原理图 主要有PWM两路输入,一路按键,两路通信口,一路PWM输出口。
至于为何要如此设计我的真的是头大,设计上有很多冗余的地方,还好我只需要完成与主mcu的交互就算完成了。
这个案子最麻烦的是通信数据没有说明,此时我也表示无奈,还好我有逻辑分析仪,只能通过仿真器模拟出下位机的应答波形,一步一步的给整个交互解码,然后把波形记录下来一个个的分析,总算是有所收获。
/* ========================================================================= * Project: GPIO_Setting * File: main.c * Description: Set GPIO of PORTB * 1. PORTB I/O state * - PB4 set input mode and enable pull-high resistor * - PB2 set output mode * - PB1 set input mode and enable pull-low resistor * - PB0 set open-drain output mode * * Author: JasonLee * Version: V1.1 * Date: 2018/09/07 =========================================================================*/ #include <ny8.h> #include "ny8_constant.h" #include <stdint.h> #define UPDATE_REG(x) __asm__("MOVR _" #x ",F") typedef union flg { uint8_t ff; struct { uint8_t flg0:1; // PWM输出控制 uint8_t flg1:1; // syatem初始化完成 uint8_t flg2:1; // bus接收/发送状态 uint8_t flg3:1; // bus读取数据锁定标志 uint8_t flg4:1; // uint8_t flg5:1; // 按键延时锁定 uint8_t flg6:1; // 按键标志有效 uint8_t flg7:1; // }; }flg; volatile flg sysflg; volatile uint8_t timclk; //volatile uint8_t secclk; volatile uint8_t comclk; //volatile uint8_t pwmclk; uint8_t delayms; //uint8_t delays; uint8_t delayclk; uint8_t revcount; //统计接收数据位 uint8_t counthi; //统计高电平连续的时间 uint8_t busdata1; //总线数据1 uint8_t busdata2; //总线数据2 uint8_t recvdata; //数据接收 //uint8_t countpwm; const uint8_t recinst1[2] = { 0x84,0x03 }; //10bit const uint8_t swinst1[2] = { 0x80,0x00 }; //10bit const uint8_t traninst7[2] = { 0x24,0x00}; const uint8_t traninst1[2] = { 0x84,0x00 }; //43bit const uint8_t traninst2[2] = { 0x24,0x00 }; //43bit const uint8_t traninst3[2] = { 0x48,0x00 }; //43bit const uint8_t traninst4[2] = { 0x50,0x00 }; //43bit const uint8_t traninst5[2] = { 0x8a,0x00 }; //43bit const uint8_t traninst6[2] = { 0x20,0x01 }; //43bit void isr_hw(void) __interrupt(0) { if(INTFbits.T0IF) { TMR0 = 56; // 32000/25/128/10 timclk++; INTFbits.T0IF = 0; } if(INTFbits.T1IF) { comclk++; if(sysflg.flg2 == 0) //bus状态模式,主程序控制 { if(PORTBbits.PB0) { //高电平超过2ms把数据清零 //高电平时读取一次数据,并发生移位 counthi++; if(counthi > 4) //判定为超时 { revcount = 0; recvdata = 0; } if(!sysflg.flg3) //锁定标志,低电平释放 { sysflg.flg3 = 1; revcount++; recvdata <<= 1; //左移移位 recvdata = recvdata + (uint8_t)(PORTBbits.PB1); if(revcount == 8) { busdata1 = recvdata; } else if(revcount == 11) { revcount = 0; busdata2 = (recvdata >>1) & 0x03; //没帧数据的结尾都会在clk低的时候拉高data,在将clk拉,需要取出掉最后一个数据位 if((busdata1 == recinst1[0] )&&(busdata2 == recinst1[1])) { //sysflg.flg4 = 1; //接收完成,接收完成清零 sysflg.flg2 = 1; } } } } else { //接收锁定标志释放 counthi = 0; sysflg.flg3 = 0; } } INTFbits.T1IF = 0; } if(INTFbits.PBIF) { if(sysflg.flg0) { PORTBbits.PB3 = !(PORTBbits.PB5); } INTFbits.PBIF = 0; } } void transbus(void) { for(revcount = 0;revcount<8;revcount++) { PORTBbits.PB0 = 0; if(busdata1 & 0x01) { PORTBbits.PB1 = 1; } else { PORTBbits.PB1 = 0; } busdata1 >>= 1; delayclk = comclk + 4; TMR1 = 125; while(delayclk != comclk); //延时1ms PORTBbits.PB0 = 1; delayclk = comclk + 4; TMR1 = 125; while(delayclk != comclk); //延时2ms } } void transdata(uint8_t i) { for(revcount = 0;revcount<i;revcount++) { while(PORTBbits.PB0); if(busdata1 & 0x01) { PORTBbits.PB1 = 1; } else { PORTBbits.PB1 = 0; } busdata1 >>= 1; while(!(PORTBbits.PB0)); } } void main(void) { sysflg.flg2 = 0; //总线为接收状态 DISI(); //;Initial GPIO BPHCON = (unsigned char)(~(C_PB2_PHB | C_PB0_PHB | C_PB1_PHB)); // Enable PB4 Pull-High Resistor,others disable IOSTB = C_PB0_Input | C_PB1_Input | C_PB2_Input | C_PB5_Input | C_PB4_Input; // Set PB4 & PB1 to input mode,others set to output mode PORTBbits.PB3 = 0; // PB2 & PB0 output high //Initial tim0 定时器中断为 32768/200/82 = 2 //系统延时,pwm输出 T0MD = C_PS0_WDT | C_TMR0_LowClk | C_TMR0_Clk; //分频器给WDT,使用指令时钟,i_lrc/ps0 = 4M, TMR0 = 56; //32000/500/53 PCON1 = C_TMR0_En; //开启定时器中断inttim1 INTE = C_INT_TMR0; //Initial tim1 //通讯时序 0.5ms TMR1 = 125; //到0下溢出中断 //4M/32/125 = 1000 T1CR1 = C_TMR1_Reload | C_TMR1_En; //自动重载 T1CR2 = C_TMR1_ClkSrc_Inst | C_PS1_EN | C_PS1_Div16; //指令时钟 //开启定时器中断inttim1 INTE = INTE | C_INT_TMR1; //PB5口电平变化中断 BWUCONbits.WUPB5 = 1; INTEbits.PBIE = 1; ENI(); while(1) { CLRWDT(); if(sysflg.flg1 == 0) //sysem初始化 { if(sysflg.flg2) //总线为发送状态 { //sysflg.flg4 = 0; { delayclk = comclk + 5; TMR1 = 125; while(delayclk != comclk); //延时2.5ms delayclk = comclk + 5; TMR1 = 125; while(delayclk != comclk); //延时2.5ms PORTBbits.PB1 = 0; IOSTB = IOSTB & (uint8_t) (~ C_PB1_Input); //切换为输出模式 busdata1 = traninst1[0]; transdata(8); busdata1 = traninst1[1]; transdata(2); while(PORTBbits.PB0); //停止位 PORTBbits.PB1 = 1; delayclk = comclk + 8; TMR1 = 125; while(delayclk != comclk); //延时4ms PORTBbits.PB1 = 0; busdata1 = traninst2[0]; transdata(8); busdata1 = traninst2[1]; transdata(2); while(PORTBbits.PB0); //停止位 PORTBbits.PB1 = 1; delayclk = comclk + 8; TMR1 = 125; while(delayclk != comclk); //延时4ms PORTBbits.PB1 = 0; busdata1 = traninst3[0]; transdata(8); busdata1 = traninst3[1]; transdata(2); while(PORTBbits.PB0); //停止位 PORTBbits.PB1 = 1; IOSTB = IOSTB | C_PB1_Input; delayclk = comclk + 126; TMR1 = 125; while(delayclk != comclk); //延时63ms PORTBbits.PB1 = 0; IOSTB = IOSTB & (uint8_t) (~ C_PB1_Input); //切换为输出模式 busdata1 = traninst4[0]; transdata(8); busdata1 = traninst4[1]; transdata(2); while(PORTBbits.PB0); //停止位 PORTBbits.PB1 = 1; delayclk = comclk + 8; TMR1 = 125; while(delayclk != comclk); //延时2ms PORTBbits.PB1 = 0; busdata1 = traninst5[0]; transdata(8); busdata1 = traninst5[1]; transdata(2); while(PORTBbits.PB0); //停止位 PORTBbits.PB1 = 1; delayclk = comclk + 8; TMR1 = 125; while(delayclk != comclk); //延时4ms PORTBbits.PB1 = 0; busdata1 = traninst6[0]; transdata(8); busdata1 = traninst6[1]; transdata(2); while(PORTBbits.PB0); //停止位 PORTBbits.PB1 = 1; IOSTB = IOSTB | C_PB1_Input; delayclk = comclk + 8; TMR1 = 125; while(delayclk != comclk); //延时4ms PORTBbits.PB1 = 1; PORTBbits.PB0 = 1; IOSTB = IOSTB = IOSTB & (uint8_t) (~ (C_PB1_Input | C_PB0_Input)); //切换为输出模式 PORTBbits.PB1 = 0; delayclk = comclk + 1; TMR1 = 125; while(delayclk != comclk); //延时0.5ms busdata1 = traninst7[0]; transbus(); revcount = 0; while(revcount < 2) { PORTBbits.PB0 = 0; PORTBbits.PB1 = 0; delayclk = comclk + 4; TMR1 = 125; while(delayclk != comclk); //延时2ms PORTBbits.PB0 = 1; delayclk = comclk + 4; TMR1 = 125; while(delayclk != comclk); //延时2ms revcount ++; } PORTBbits.PB0 = 0; PORTBbits.PB1 = 1; delayclk = comclk + 4; TMR1 = 125; while(delayclk != comclk); //延时2ms PORTBbits.PB0 = 1; delayclk = comclk + 4; TMR1 = 125; while(delayclk != comclk); //延时2ms sysflg.flg1 = 1; //切换总线输出状态 } } } else //初始化完成 { if(PORTBbits.PB2 == 0) //检测按键 { if(sysflg.flg5 == 0) { sysflg.flg5 = 1; delayclk = comclk + 30; TMR1 = 125; //32000/500/53 } if(delayclk == comclk); //延时32ms { //按键标志有效 sysflg.flg6 = 1; } } else { sysflg.flg5 = 0; if(sysflg.flg6) { sysflg.flg6 = 0; //向主mcu发数据 PORTBbits.PB1 = 0; delayclk = comclk + 1; TMR1 = 125; while(delayclk != comclk); //延时0.5ms busdata1 = swinst1[0]; transbus(); revcount = 0; while(revcount < 2) { PORTBbits.PB0 = 0; PORTBbits.PB1 = 0; delayclk = comclk + 4; TMR1 = 125; while(delayclk != comclk); //延时2ms PORTBbits.PB0 = 1; delayclk = comclk + 4; TMR1 = 125; while(delayclk != comclk); //延时2ms revcount ++; } PORTBbits.PB0 = 0; PORTBbits.PB1 = 1; delayclk = comclk + 4; TMR1 = 125; while(delayclk != comclk); //延时2ms PORTBbits.PB0 = 1; delayclk = comclk + 4; TMR1 = 125; while(delayclk != comclk); //延时2ms sysflg.flg0 ^= 1; //countpwm = 0; //PORTBbits.PB4 = 0; PORTBbits.PB3 = 0; //PORTBbits.PB5 = 0; } if((sysflg.flg0 == 1)&&(PORTBbits.PB5 == 0)&&(sysflg.flg6 == 0)) { if(sysflg.flg7 == 0) { sysflg.flg7 = 1; delayms = timclk + 82; TMR0 = 56; } if(delayms == timclk) { sysflg.flg0 = 0; PORTBbits.PB3 = 0; } } else { sysflg.flg7 = 0; } } } } }
8位单片机项目可以找我:18665321219