1、2脚IIC时钟线,3脚输出高电平,5脚输出IIC数据线,6脚传感器中断脚,7脚按钮, 2.按键启动,3脚输出低电平,读取传感器ID,启动传感器,5分钟内振动重新定时,5分钟内关闭。按钮再次关闭。 当传感器无法读取时ID闪烁5秒后关机(2HZ) 4.当电源电压低于3时.30V闪烁10秒后关机(1HZ)
/* ========================================================================= * Project: SPC03 * Author: WANG ZHAOZHAO * Date: 2022.05.05 =========================================================================*/ #include <ny8.h> #include <ny8_romaccess.h> #include "ny8_constant.h" typedef unsigned char u8; typedef unsigned int u16; typedef unsigned long int u32; ///// #define PIN_IIC_SCL PB5 // #define PIN_LED_D0 PB4 // #define PIN_PB3 PB3 // #define PIN_KEY_SWITCH PB0 // #define PIN_DA260B_INT PB1 // #define PIN_IIC_SDA PB2 // / #define KEY_NUMBER 1 //按键数量 #define KEY_SHORT_TIMES 2 //按键短按时间 #define KEY_LONG_TIMES 200 //按键长按时间 #define KEY_HOLD_TIMES (200 50) //按键连按时间 #define KEY_DOUBLE_TIMES 40 //按键双击时间 #define NO_KEY_PRESS 0xff //没有按键 #define NO_KEY_MSG 0xfe //没有按键消息 #define KEY_HOLD (1<<4) //连按 #define KEY_LONG (1<<5) //长按按下 #define KEY_DOUBLE (1<<6) //双击按下 #define KEY_HOLD_DQ (1<<7) //连按抬起 #define KEY_SWITCH 0x01 //开关(短按抬起) #define KEY_SWITCH_HOLD (KEY_SWITCH | KEY_HOLD) #define KEY_SWITCH_LONG (KEY_SWITCH | KEY_LONG) #define KEY_SWITCH_DOUBLE (KEY_SWITCH | KEY_DOUBLE) #define KEY_SWITCH_HOLD_DQ (KEY_SWITCH | KEY_HOLD_DQ) static unsigned char KeySignalCount; static unsigned char key_msg = NO_KEY_MSG; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// typedef union { struct { u8 bit0 : 1; u8 bit1 : 1; u8 bit2 : 1; u8 bit3 : 1; u8 bit4 : 1; u8 bit5 : 1; u8 bit6 : 1; u8 bit7 : 1; } bits; }Flag; volatile Flag sys_flag; volatile Flag bat_flag; volatile Flag time_flag; #define sys_power_flag sys_flag.bits.bit0 //上电标志 #define sys_sleep_flag sys_flag.bits.bit1 //睡眠标志 #define sys_work_flag sys_flag.bits.bit2 //工作标志 #define sys_work_key_flag sys_flag.bits.bit3 //工作按键标志 #define sys_work_led_flag sys_flag.bits.bit4 //工作闪灯标志 #define sys_work_mode_flag sys_flag.bits.bit5 //工作模式标志 #define sys_work_stop_flag sys_flag.bits.bit6 // #define bat_discharge_flag bat_flag.bits.bit0 ///电池放电标志 #define bat_charge_flag bat_flag.bits.bit1 //电池充电标志 #define bat_charge_full_flag bat_flag.bits.bit2 //电池充满标志 #define bat_battery_low_flag bat_flag.bits.bit3 //电池低电标志 #define time_1s_flag time_flag.bits.bit0 //1s时间标志 #define time_1ms_flag time_flag.bits.bit1 //1ms时间标志 #define time_10ms_flag time_flag.bits.bit2 //10ms时间标志 #define time_100ms_flag time_flag.bits.bit3 //100ms时间标志 #define time_500ms_flag time_flag.bits.bit4 //500ms时间标志 //// #define IIC_ADDR_Def 0x4e //IIC地址 #define SDA_IN {IOSTB|= 0x04; PHPB2=0;} //输入 #define SDA_OUT IOSTB &= 0xFB; //输出 #define IIC_SCL PB5 #define IIC_SDA PB2 #define READ_SDA PB2 #define REG_SPI_I2C 0x00 #define REG_CHIPID 0x01 #define REG_ACC_X_LSB 0x02 #define REG_ACC_X_MSB 0x03 #define REG_ACC_Y_LSB 0x04 #define REG_ACC_Y_MSB 0x05 #define REG_ACC_Z_LSB 0x06 #define REG_ACC_Z_MSB 0x07 #define REG_MOTION_FLAG 0x09 #define REG_NEWDATA_FLAG 0x0A #define REG_ACTIVE_STATUS 0x0B #define REG_G_RANGE 0x0F #define REG_ODR_AXIS_DISABLE 0x10 #define REG_POWERMODE_BW 0x11 #define REG_SWAP_POLARITY 0x12 #define REG_INTERRUPT_SETTINGS1 0x16 #define REG_INTERRUPT_SETTINGS2 0x17 #define REG_INTERRUPT_MAPPING1 0x19 #define REG_INTERRUPT_MAPPING2 0x1A #define REG_INT_PIN_CONFIG 0x20 #define REG_INT_LATCH 0x21 #define REG_ACTIVE_DURATION 0x27 #define REG_ACTIVE_THRESHOLD 0x28 //// u8 timer_count0; //定时记数 u8 timer_count1; //定时记数 u8 resslt_value; //传感器返回值 u8 bat_battery_lowH_count; ///电池低电高电平计数 u8 bat_battery_lowL_count; ///电池低电低电平计数 u8 sys_da260b_intH_count; ///传感器断脚高电平计数 u8 sys_da260b_intL_count; //传感器断脚低电平计数
u8 sys_da260b_intSUM_count; //传感器中断脚总变化计数
u8 sys_work_stop_time; //LED闪烁时间(次数*频率)
u8 sys_work_stop_count; //LED闪烁时间时间计数
u8 sys_work_stop_prequency; //LED闪烁频率
u16 sys_timing_value; //自动关机定时(秒)
/************************************************
; * @Function Name : Delay_Ms
; * @Description : Simple delay function
; * @IN_Parameter :
; * @Return parameter :
; ***********************************************/
void Delay_Ms(u8 ms)
{
u8 i = 0;
while(ms--)
{
for(i = 0; i < 251; i++)
{
;
}
}
}
/************************************************
; * @Function Name : Delay_Us
; * @Description : Simple delay function
; * @IN_Parameter :
; * @Return parameter :
; ***********************************************/
void Delay_Us(void)
{
NOP();NOP();NOP();NOP();NOP();
}
//产生IIC起始信号
void IIC_Start(void)
{
SDA_OUT //sda线输出
IIC_SDA = 1;
IIC_SCL = 1;
Delay_Us();
IIC_SDA = 0;
Delay_Us();
IIC_SCL = 0; //拉低I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void IIC_Stop(void)
{
SDA_OUT //sda线输出
IIC_SCL = 0;
IIC_SDA = 0;
Delay_Us();
IIC_SCL = 1;
Delay_Us();
IIC_SDA = 1; //发送I2C总线结束信号
Delay_Us();
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime = 0;
SDA_IN //SDA设置为输入
IIC_SDA = 1;
Delay_Us();
IIC_SCL = 1;
Delay_Us();
while (READ_SDA)
{
ucErrTime++;
if (ucErrTime > 250)
{
IIC_Stop();
return 1;
}
}
Delay_Us();
IIC_SCL = 0; //时钟输出0
return 0;
}
//产生ACK应答
void IIC_Ack(void)
{
IIC_SCL = 0;
SDA_OUT
IIC_SDA = 0;
Delay_Us();
IIC_SCL = 1;
Delay_Us();
IIC_SCL = 0;
}
//不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL = 0;
SDA_OUT
IIC_SDA = 1;
Delay_Us();
IIC_SCL = 1;
Delay_Us();
IIC_SCL = 0;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT
IIC_SCL = 0; //拉低时钟开始数据传输
for (t = 0; t < 8; t++)
{
IIC_SDA = (txd & 0x80) >> 7;
txd <<= 1;
//Delay_Us();
IIC_SCL = 1;
Delay_Us();
IIC_SCL = 0;
Delay_Us();
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(u8 ack)
{
u8 i, receive;
SDA_IN //SDA设置为输入
receive=0;
for (i = 0; i < 8; i++)
{
IIC_SCL = 0;
Delay_Us();
IIC_SCL = 1;
receive <<= 1;
if (READ_SDA)
{
receive++;
}
Delay_Us();
}
if (!ack)
IIC_NAck(); //发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
/************************************************
; * @Function Name : PIC_ReadOneByte();
; * @Description : 在XXXXXX指定地址读出一个数据
; * @IN_Parameter :
ReadAddr:开始读数的地址
DataToWrite:要写入的数据
; * @Return parameter : =0:错误数据, !=0:读到的数据
; ***********************************************/
u8 PIC_ReadOneByte(u8 ReadAddr)
{
u8 res=0;
u8 temp=0;
CLRWDT();
IIC_Start();
IIC_Send_Byte(IIC_ADDR_Def); //发送器件地址,写数据
res|=IIC_Wait_Ack();
IIC_Send_Byte(ReadAddr); //发送低地址
res|=IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(IIC_ADDR_Def+1); //进入接收模式
res|=IIC_Wait_Ack();
temp = IIC_Read_Byte(0);
IIC_Stop(); //产生一个停止条件
if(res)
return 0;
else
return temp;
}
/************************************************
; * @Function Name : PIC_WriteOneByte();
; * @Description : 在XXXXXX指定地址写入一个数据
; * @IN_Parameter :
WriteAddr :写入数据的目的地址
DataToWrite:要写入的数据
; * @Return parameter : 0:成功, 1:失败
; ***********************************************/
u8 PIC_WriteOneByte(u8 WriteAddr, u8 DataToWrite)
{
u8 res=0;
CLRWDT();
IIC_Start();
IIC_Send_Byte(IIC_ADDR_Def); //发送器件地址0XA0,写数据
res|=IIC_Wait_Ack();
IIC_Send_Byte(WriteAddr); //发送低地址
res|=IIC_Wait_Ack();
IIC_Send_Byte(DataToWrite); //发送字节
res|=IIC_Wait_Ack();
IIC_Stop(); //产生一个停止条件
Delay_Ms(10); //EEPROM的写入速度比较慢,加入延迟
return res;
}
/************************************************
; * @Function Name : DA260B_Open_Interrupt();
; * @Description : open active interrupt
; * @IN_Parameter : th 时间值
; * @Return parameter : 0:成功, 1:失败
; ***********************************************/
u8 DA260B_Open_Interrupt(u8 th)
{
u8 res = 0;
res|=PIC_WriteOneByte(REG_INTERRUPT_SETTINGS1,0x87); //打开轴触发中断
//res|=PIC_WriteOneByte(NSA_REG_INTERRUPT_SETTINGS2,0x10); //打开新的数据中断
res|=PIC_WriteOneByte(REG_INT_PIN_CONFIG,0x03); //设置为推挽输出,触发中断输出高电平
res|=PIC_WriteOneByte(REG_ACTIVE_DURATION,0x00); //中断持续时间
res|=PIC_WriteOneByte(REG_ACTIVE_THRESHOLD,th); //设置中断时间(中断时间=th*3.91)
res|=PIC_WriteOneByte(REG_INTERRUPT_MAPPING1,0x04); //映射到INT
return res;
}
/************************************************
; * @Function Name : DA260B_Close_Interrupt();
; * @Description : close active interrupt
; * @IN_Parameter : th 时间值
; * @Return parameter : 0:成功, 1:失败
; ***********************************************/
u8 DA260B_Close_Interrupt(void)
{
u8 res = 0;
res|=PIC_WriteOneByte(REG_INTERRUPT_SETTINGS1,0x00);//关闭中断
res|=PIC_WriteOneByte(REG_INTERRUPT_MAPPING1,0x00); //关闭映射
return res;
}
/************************************************
; * @Function Name : Work_Detection();
; * @Description : DA260B初始化
; * @IN_Parameter : void
; * @Return parameter : 0:成功, 1:失败
; ***********************************************/
u8 DA260B_Init(void)
{
u8 res = 0;
u8 temp = 0;
//read chip id
temp=PIC_ReadOneByte(REG_CHIPID);
temp=PIC_ReadOneByte(REG_CHIPID);
if(temp == 0x13)
{
//读取ID成功
res|=PIC_WriteOneByte(REG_SPI_I2C,0x24); //软件复位
res|=PIC_WriteOneByte(REG_G_RANGE, 0x00); //+/-2G,14bit
res|=PIC_WriteOneByte(REG_ODR_AXIS_DISABLE, 0x07); //ODR = 125hz
res|=PIC_WriteOneByte(REG_POWERMODE_BW, 0x02); //normal mode
//中断设置
//res|=DA260B_Open_Interrupt(10);
res|=PIC_WriteOneByte(REG_INTERRUPT_SETTINGS1,0x87); //打开轴触发中断
res|=PIC_WriteOneByte(REG_INT_PIN_CONFIG,0x03); //设置为推挽输出,输出低电平
res|=PIC_WriteOneByte(REG_ACTIVE_DURATION,0x00); //中断持续时间
res|=PIC_WriteOneByte(REG_ACTIVE_THRESHOLD,10); //设置中断时间(中断时间=th*3.91)
res|=PIC_WriteOneByte(REG_INTERRUPT_MAPPING1,0x04); //映射到INT
}
else
{
//读取ID失败
res=1;
}
return res;
}
/************************************************
; * @Function Name : IO_Init
; * @Description : io口初始化
; * @IN_Parameter :
; * @Return parameter :
; ***********************************************/
void Configuration_Init(void)
{
IOSTB = 0x0b; // 1 输入模式。0 输出模式。 GP7、GP6:通用寄存器位。
PORTB = 0x10; // 1 高电平状态。0 低电平状态
BWUCON = 0x01; // 1 开启PBx唤醒功能。0 关闭PBx唤醒功能。
BODCON = 0x00; // 1 开漏输出。0 推挽输出。
BPLCON = 0xfd; // 1 关闭PBx拉低电阻。0 使能PBx拉低电阻。
BPHCON = 0xfa; // 1 关闭PBx拉高电阻。0 使能PBx拉高电阻。
INTF = 0; // 清除中断标志位
DISI(); // 禁用所有未屏蔽中断
//;Initial Timer0
PCON1 = C_TMR0_En; // 禁用Timer0
TMR0 = 0; // 初始Timer0寄存器
T0MD = C_PS0_TMR0 | C_PS0_Div16; // 时钟为指令时钟 定时器4分频 1ms
//;Initial Timer1
//TMR1 = 34;//111KHz // 初始Timer1寄存器
//T1CR1 = C_TMR1_Reload | C_TMR1_En | C_PWM1_En;// 启用Timer1,从TMR1重新加载初始值,不间断模式,PWM1使能
//T1CR2 = C_TMR1_ClkSrc_Inst | C_PS1_Div2; // 时钟为指令时钟 定时器4分频 1ms
//PWM1DUTY = 0; // PWM1占空比
//;Setting Interrupt Enable Register
//INTE = C_INT_WDT | C_INT_TMR1 | C_INT_TMR0; // 启用Timer0, Timer1, WDT溢出中断
INTE = C_INT_WDT | C_INT_TMR0; // 启用Timer0, WDT溢出中断
//;Initial Power control register
PCON = C_WDT_En | C_LVR_En | C_LVD_En; // 启用WDT,启用LVR,启用LVD
//;Enable Timer0 & Global interrupt bit
PCON1 = C_LVD_3P3V | C_TMR0_En; // 启用Timer0
ENI(); // 启用所有未屏蔽中断
//;初始化变量
sys_power_flag=0;
sys_sleep_flag=0;
sys_work_flag=0;
sys_work_key_flag=0;
sys_work_led_flag=0;
sys_work_stop_flag=0;
time_1s_flag=0;
time_1ms_flag=0;
timer_count0=0;
timer_count1=0;
}
/************************************************
; * @Function Name : Key_Scan();
; * @Description : 按键扫描检测
; * @IN_Parameter : void
; * @Return parameter : 确认的按键信息
; ***********************************************/
char Key_Scan(void)
{
char KeyValue = NO_KEY_MSG;//用于返回按键稳定的值
if(!PIN_KEY_SWITCH) //低有效
{
if(KeySignalCount <= KEY_HOLD_TIMES)
KeySignalCount++;
if(KeySignalCount == KEY_LONG_TIMES)
{
KeyValue = (0x01 | KEY_LONG);
}
}
else
{
if((KeySignalCount > KEY_SHORT_TIMES)
&&(KeySignalCount < KEY_LONG_TIMES))
{
KeyValue = 0x01;
}
KeySignalCount = 0;
}
return KeyValue;
}
/************************************************
; * @Function Name : Key_Message_Dispose();
; * @Description : 按键消息处理
; * @IN_Parameter : void
; * @Return parameter : void
; ***********************************************/
void Key_Message_Dispose(void)
{
if(KEY_SWITCH == key_msg)
{
if(0 == sys_work_stop_flag)
{
if(sys_work_flag)
{
PIN_LED_D0=1;
PIN_IIC_SCL=0;
PIN_IIC_SDA=0;
sys_work_flag=0;
sys_work_key_flag=0;
sys_timing_value=0;
//PIC_WriteOneByte(NSA_REG_INTERRUPT_SETTINGS1,0x00);//关闭中断
//PIC_WriteOneByte(NSA_REG_INTERRUPT_MAPPING1,0x00); //关闭映射
}
else
{
PIN_LED_D0=0;
sys_work_flag=1;
sys_work_key_flag=1;
sys_work_stop_count=0;
sys_timing_value=298;
sys_da260b_intSUM_count=0;
}
}
}
}
/************************************************
; * @Function Name : Work_Detection();
; * @Description :
; * @IN_Parameter : void
; * @Return parameter : void
; ***********************************************/
void Work_Detection(void)
{
//传感器
if(sys_work_key_flag)
{
sys_work_key_flag=0;
resslt_value=DA260B_Init();//传感器初始化
if(0 != resslt_value)
{
resslt_value=0;
PIN_LED_D0=1;
PIN_IIC_SCL=0;
PIN_IIC_SDA=0;
sys_work_flag=0;
sys_work_stop_flag=1;
sys_work_stop_time=20;
sys_work_stop_count=0;
sys_work_stop_prequency=25;
}
}
//低电
if(sys_work_flag)
{
if(bat_battery_low_flag)
{
sys_work_stop_count++;
if(50<=sys_work_stop_count)
{
PIN_LED_D0=1;
PIN_IIC_SCL=0;
PIN_IIC_SDA=0;
sys_work_flag=0;
sys_work_stop_flag=1;
sys_work_stop_time=20;
sys_work_stop_count=0;
sys_work_stop_prequency=50;
}
}
}
//传感器初始化失败或者低电的提示闪烁
if(sys_work_stop_flag)
{
sys_work_stop_count++;
if(sys_work_stop_prequency<=sys_work_stop_count)
{
sys_work_stop_count=0;
if(PIN_LED_D0)
PIN_LED_D0=0;
else
PIN_LED_D0=1;
if(sys_work_stop_time)
{
sys_work_stop_time--;
}
else
{
PIN_LED_D0=1;
sys_work_flag=0;
sys_work_stop_flag=0;
}
}
}
}
/************************************************
; * @Function Name : IO_Detection();
; * @Description : IO检测
; * @IN_Parameter : void
; * @Return parameter : void
; ***********************************************/
void IO_Detection(void)
{
//低电检测
if(PCON1 & 0X40)
{
bat_battery_lowL_count=0;
if(200>bat_battery_lowH_count)
bat_battery_lowH_count++;
}
else
{
bat_battery_lowH_count=0;
if(200>bat_battery_lowL_count)
bat_battery_lowL_count++;
}
if(20<bat_battery_lowL_count)
{
bat_battery_low_flag=1;
}
if(20<bat_battery_lowH_count)
{
bat_battery_low_flag=0;
}
//传感器中断检测
if(sys_work_flag)
{
if(PIN_DA260B_INT)
{
sys_da260b_intL_count=0;
if(200>sys_da260b_intH_count)
sys_da260b_intH_count++;
else
sys_timing_value=298;
}
else
{
sys_da260b_intH_count=0;
if(200>sys_da260b_intL_count)
sys_da260b_intL_count++;
else
sys_da260b_intSUM_count=0;
}
if((1>=sys_da260b_intL_count)&&(1>=sys_da260b_intH_count))
{
if(20>sys_da260b_intSUM_count)
sys_da260b_intSUM_count++;
else
{
sys_timing_value=298;
}
}
}
}
/************************************************
; * @Function Name : Sleep_Mode();
; * @Description : 低功耗模式检测
; * @IN_Parameter : void
; * @Return parameter : void
; ***********************************************/
void Sleep_Mode(void)
{
if((0 == sys_work_flag) && (0 == sys_work_stop_flag))//没有在工作
{
PIN_LED_D0=1;
PIN_IIC_SCL=0;
PIN_IIC_SDA=0;
sys_sleep_flag=1;
}
if(1 == sys_sleep_flag)
{
sys_sleep_flag=0;
INTE = C_INT_PBKey;
INTF = 0;
CLRWDT();
NOP();
SLEEP();
NOP();
CLRWDT();
INTE = C_INT_TMR0;
}
}
/************************************************
; * @Function Name : main
; * @Description :
; * @IN_Parameter :
; * @Return parameter :
; ***********************************************/
void main(void)
{
Configuration_Init();
while(1)
{
CLRWDT();
if(time_10ms_flag)
{
time_10ms_flag=0;
key_msg = Key_Scan(); //按键扫描
Key_Message_Dispose(); //按键处理
Work_Detection();
IO_Detection();
}
if(time_1s_flag)
{
time_1s_flag=0;
Sleep_Mode();
if(sys_work_flag)
{
if(sys_timing_value)
sys_timing_value--;
else
{
PIN_LED_D0=1;
sys_work_flag=0;
sys_work_key_flag=0;
sys_work_stop_flag=0;
sys_timing_value=0;
}
}
}
}
}
/************************************************
; * @Function Name : Interrupt
; * @Description : The interrupt function
; * @IN_Parameter :
; * @Return parameter :
; ***********************************************/
void isr(void) __interrupt(0)
{
if(INTFbits.T0IF)//定时器0
{
TMR0 = 0; //1ms
INTFbits.T0IF = 0; // Clear T0IF flag bit
timer_count0++;
if(10 <= timer_count0) //10ms
{
timer_count0=0;
time_10ms_flag=1;
timer_count1++;
if(100 <= timer_count1) //1s
{
timer_count1=0;
time_1s_flag=1;
}
}
}
}