曾经遇到一个案子,需要用到8位单片机做密码锁,主mcu只有与8位单片机完成交互(数据密钥传输)才可以正常使用,案子虽然完成了但是至今我都没有理解到底密码是多少,写案子总结的时候完全是通过示波器抓取通信波形来表达的。

见原理图 主要有PWM两路输入,一路按键,两路通信口,一路PWM输出口。

单片机私有通信协议 密码锁_ios​​单片机私有通信协议 密码锁_单片机_02

至于为何要如此设计我的真的是头大,设计上有很多冗余的地方,还好我只需要完成与主mcu的交互就算完成了。

这个案子最麻烦的是通信数据没有说明,此时我也表示无奈,还好我有逻辑分析仪,只能通过仿真器模拟出下位机的应答波形,一步一步的给整个交互解码,然后把波形记录下来一个个的分析,总算是有所收获。

单片机私有通信协议 密码锁_数据_03

/* =========================================================================
* 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;
}
}
}
}
}