本帖最后由 szkeinew 于 2020-4-10 23:41 编辑
上接【赛元95F】——低功耗电容式接近触摸感应水龙头(一)https://bbs.21ic.com/icview-2939306-1-1.html?fromuser=szkeinew
一,框图及流程图如下:
二,触摸库调试简图:
三,程序部分内容展示:
//主程序
#include "sys_variable.h"
void SYS_INIT(void); //系统初始化
void TOUCH_KEY(void); //触摸键处理
void SOLENOID_VALVE_RESET(void); //电磁阀复位
void SLEEP_FRONT_RESET(void); //休眠前复位
void ADC_CHECK_FUNCTION(void); //ADC检测
void BAT_CHARGE_FUNCTION(void); //电池充电
void SLEEP_FUNCTION(void); //休眠
void main(void){
SYS_INIT();
while(1){
TOUCH_KEY();
}
}
void SYS_INIT(void){
//端口复位
GPIO_INIT(GPIO0,0XEF,0X10,0XDF);
GPIO_INIT(GPIO1,0XFF,0X00,0XCF);
GPIO_INIT(GPIO2,0XF2,0X00,0XFF);
GPIO_INIT(GPIO3,0XFF,0X00,0XFF);
GPIO_INIT(GPIO4,0XFF,0X00,0XFF);
GPIO_INIT(GPIO5,0XFF,0X00,0XF7);
SOLENOID_VALVE_RESET();
ADC_INIT(FADC32);
ADC_SWITCH(AIN6);//VIN_ADC
ADC_SWITCH(AIN7);//BAT_ADC
adc_select_chan = AIN6;
ADC_ADCIF_RESET_FLAG();
INTERRUPT_INIT(ADC,1);
ADC_EN(1);
ADC_SWITCH(adc_select_chan);//VIN_ADC
ADC_START();
while(BAT_VOLTAGE() < 1.0F);
TouchKeyInit();
INTERRUPT_INIT(Timer0,1);
timer0_timing_value = TIMER0_INIT(TIMER0BITS_16BIT,CONTROLMODE_TIMING,FREQ_SELECT_1DIV,10000);//10ms
TIMER0_TIMING_SET(timer0_timing_value);
TIMER0_SWITCH(1);
LED1_FUN_EN(1);
LED2_FUN_EN(1);
while(!sys_reset_finish_flag); //第一次上电要长启动,防止由于上电期触控误工作,令电磁阀开启
LED1_FUN_EN(0);
LED2_FUN_EN(0);
polarity_reset_flag = 1;
adc_check_time = ADC_CHECK_TIME_VALUE - 3;
BTM_INIT(BTM_1S);
//sys_fun_error_flag = 1;
}
void SOLENOID_VALVE_RESET(void){
INTERRUPT_INIT(INT2,1);
INT2R |= 0X01; //上升沿触发
PWR_FUN_EN(1);
DELAY_MS(50);
POLARITY_SELECT(1,1);
DELAY_MS(20);
POLARITY_SELECT(1,0);
PWR_FUN_EN(0);
INTERRUPT_INIT(INT2,0);
INT2R &= 0XFE; //取消上升沿触发
}
void TOUCH_KEY(void){
if((SOCAPI_TouchKeyStatus & 0x80) == 0x80){
SOCAPI_TouchKeyStatus &= 0x7f;
touch_select_valid_flag = 0;
if(touch_start_number >= TOUCH_START_NUMBER_VALUE){
if((TouchKeyScan() & 0x00000080) == 0x00000080){
touch_select_valid_flag = 1;//((TouchKeyScan() & 0x00000080) >> 7) & 0x01;
}
/**************
触摸有效值是当前与上一次的值同时一样才能判断当次有效,
这样才能最大地避免误判,提高稳定度。
**************/
if(touch_select_valid_flag && touch_select_valid_history_flag){
touch_check_number++;
if(touch_check_number >= (TOUCH_CHECK_NUMBER_VALUE/4)){
touch_unselect_count = 0;
}
if(touch_check_number >= TOUCH_CHECK_NUMBER_VALUE){
touch_check_number = TOUCH_CHECK_NUMBER_VALUE;
/*
if(~polarity_reset_flag){
LED1_FUN_EN((work_timing_time >= WORK_TIMING_TIME_VALUE)?0:1);
}else{
LED1_FUN_EN();
}*/
TIMER0_SWITCH(1);
if(!work_timeout_flag){
polarity_reset_flag = 0;
LED1_FUN_EN(1);
}else{
LED1_FUN_EN(0);
}
//LED2_FUN_EN(0);
}
}else{
LED1_FUN_EN(0);
touch_unselect_count++;
if((touch_unselect_count >= (TOUCH_UNSELECT_COUNT_VALUE/4)) ||
(touch_check_number == TOUCH_CHECK_NUMBER_VALUE)){
touch_check_number = 0;
}
touch_check_number = 0;
if(touch_unselect_count >= TOUCH_UNSELECT_COUNT_VALUE){
touch_unselect_count = 0;
if(!polarity_reset_flag){
polarity_reset_flag = 1;
work_timing_time = 0;
while(polarity_reset_flag);
}
work_timeout_flag = 0;
SLEEP_FRONT_RESET();
}
}
touch_select_valid_history_flag = touch_select_valid_flag;
}else{
PWR_FUN_EN(0);
touch_select_valid_flag = (TouchKeyScan() & 0x00000000);
}
touch_start_number++;
TouchKeyRestart();
}
}
void SLEEP_FRONT_RESET(void){
TK_POWER_EN(0);
TIMER0_SWITCH(0);
LED1_FUN_EN(0);
touch_check_number = 0;
touch_unselect_count = 0;
work_timing_time = 0;
touch_select_valid_flag = 0;
touch_start_number = 0;
polarity_reset_flag = 1;
if(BAT_CHRG){
bat_charge_error_flag = 0;
LED2_FUN_EN(bat_charge_error_flag);
}
INTERRUPT_INIT(INT2,0);
INT2R &= 0XFE;
WORK_SLEEP_TEST = 1;
SLEEP_FUNCTION();
WORK_SLEEP_TEST = 0;
if(!sys_fun_error_flag){
ADC_CHECK_FUNCTION();
INTERRUPT_INIT(INT2,1);
INT2R |= 0X01; //上升沿触发
SOCAPI_TouchKeyStatus &= 0x7f;
TK_POWER_EN(1);
DELAY_MS(2);//待触摸电源稳后才工作
}else{
while(1){
SLEEP_FUNCTION();
sys_fun_error_led_disp_flag = ~sys_fun_error_led_disp_flag;
LED1_FUN_EN(!sys_fun_error_led_disp_flag);
LED2_FUN_EN(sys_fun_error_led_disp_flag);
DELAY_MS(5);
LED1_FUN_EN(0);
LED2_FUN_EN(0);
}
}
}
void SLEEP_FUNCTION(void){
INTERRUPT_INIT(BTM,1);
BTM_EN(1);
PCON |= 0x02;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
BTM_EN(0);
INTERRUPT_INIT(BTM,0);
}
void ADC_CHECK_FUNCTION(void){
adc_check_time++;
if(adc_check_time >= ADC_CHECK_TIME_VALUE){ //一分钟检测一次
adc_check_time = 0;
adc_select_chan = AIN6;
ADC_ADCIF_RESET_FLAG();
INTERRUPT_INIT(ADC,1);
ADC_EN(1);
ADC_SWITCH(adc_select_chan);//VIN_ADC
ADC_START();
while(!adc_finish_flag);
adc_finish_flag = 0;
BAT_CHARGE_FUNCTION();
}else if((adc_check_time == 25) || (adc_check_time == 50)){
TouchKeyInit();
}
}
void BAT_CHARGE_FUNCTION(void){
if(BAT_VOLTAGE() < BAT_MIN_VOLTAGE){
if(POWER_VIN_VOLTAGE() >= POWER_IN_MIN_VOLTAGE){
//电池电压低于设定最小值并输入电压大于最小值时就充电
//并且橙色指示灯长亮
BAT_CHRG_FUN_EN(1);
LED2_FUN_EN(1);
}else if(BAT_CHRG){
//如果电池电压低于设定最小值并无输入电压,则橙色指示灯闪烁指示
bat_charge_error_flag = ~bat_charge_error_flag;
LED2_FUN_EN(bat_charge_error_flag);
BAT_CHRG_FUN_EN(0);
adc_check_time = ADC_CHECK_TIME_VALUE - 3; //如果电池出现低电压,则将ADC检测时间缩短到3S
}
}else if(BAT_CHRG && (BAT_VOLTAGE() >= BAT_MAX_VOLTAGE)){
//充电完成后关闭橙色指示灯及充电端口
BAT_CHRG_FUN_EN(0);
LED2_FUN_EN(0);
}
}
//中断
#include "sys_interrupt.h"
#define ARRAY_SUB 5
uint idata ADC_TEMP_ARRAY[ARRAY_SUB] = {0,0,0,0,0};
uchar idata adc_temp_array_number = 0;
bit bittest = 0;
void INTERRUPT_INIT(enum INTERRUPTENUM enummane,bit en){
switch(enummane){
case INT0: en ?(IE |= 0X01):(IE &= 0XFE);
break;
case Timer0: en ?(IE |= 0X02):(IE &= 0XFD);
break;
case INT1: en ?(IE |= 0X04):(IE &= 0XFB);
break;
case Timer1: en ?(IE |= 0X08):(IE &= 0XF7);
break;
case UART: en ?(IE |= 0X10):(IE &= 0XEF);
break;
case Timer2: en ?(IE |= 0X20):(IE &= 0XDF);
break;
case ADC: en ?(IE |= 0X40):(IE &= 0XBF);
break;
case USCI0: en ?(IE1 |= 0X01):(IE1 &= 0XFE);
break;
case PWM: en ?(IE1 |= 0X02):(IE1 &= 0XFD);
break;
case BTM: en ?(IE1 |= 0X04):(IE1 &= 0XFB);
break;
case INT2: en ?(IE1 |= 0X08):(IE1 &= 0XF7);
break;
case TK: en ?(IE1 |= 0X10):(IE1 &= 0XEF);
break;
case CMP: en ?(IE1 |= 0X20):(IE1 &= 0XDF);
break;
case Timer3: en ?(IE1 |= 0X40):(IE1 &= 0XBF);
break;
case Timer4: en ?(IE1 |= 0X80):(IE1 &= 0X7F);
break;
case USCI1: en ?(IE2 |= 0X01):(IE2 &= 0XFE);
break;
case USCI2: en ?(IE2 |= 0X02):(IE2 &= 0XFD);
break;
}
IE |= 0x80;
}
void INTERRUPT_INT0(void) interrupt 0{
}
void INTERRUPT_TIMER0(void) interrupt 1{
TCON &= 0XDF;//清除中断标志
TIMER0_TIMING_SET(timer0_timing_value);
if(sys_reset_finish_flag){
work_timing_time++;
if(work_timing_time >= WORK_TIMING_TIME_VALUE){
if(!work_timeout_flag){
work_timing_time = 0;
work_timeout_flag = 1;
polarity_reset_flag = 1;
}else if(!polarity_reset_flag){
work_timing_time = WORK_TIMING_TIME_VALUE;
}
}else{
//开启及关闭电磁阀
if(work_timing_time < 30){
//TK_POWER_EN(0);
PWR_FUN_EN(1);
if((work_timing_time < 25 ) && (work_timing_time > 15)){
if(!polarity_reset_flag){
POLARITY_SELECT(0,1);
}else{
POLARITY_SELECT(1,1);
}
}
}else{
POLARITY_SELECT(1,0);
PWR_FUN_EN(0);
if(polarity_reset_flag){
polarity_reset_flag = 0;
}
if(work_timing_time == 50){
//SOCAPI_TouchKeyStatus &= 0x7f;
//TK_POWER_EN(1);
}
}
}
}else if(!sys_reset_finish_flag){
work_timing_time++;
if(work_timing_time >= (WORK_TIMING_TIME_VALUE*2)){
work_timing_time = 0;
sys_reset_finish_flag = 1;
TIMER0_SWITCH(0);
}
}
}
void INTERRUPT_TIMER2(void) interrupt 5{
//T2CON &= 0X7F;//清除中断标志
}
void INTERRUPT_ADC(void) interrupt 6{
uchar idata forx = 0;
uchar idata fory = 0;
uint idata temp = 0;
ADC_ADCIF_RESET_FLAG();
ADC_TEMP_ARRAY[adc_temp_array_number] = ((ADCVH << 4) |(ADCVL >> 4));
adc_temp_array_number++;
if(adc_temp_array_number > sizeof(ADC_TEMP_ARRAY[ARRAY_SUB])){
//排序
adc_temp_array_number = 0;
for(forx = 0;forx < (sizeof(ADC_TEMP_ARRAY[ARRAY_SUB])-1);forx++){
for(fory = 0;fory < (sizeof(ADC_TEMP_ARRAY[ARRAY_SUB])-1);fory++){
if(ADC_TEMP_ARRAY[fory] > ADC_TEMP_ARRAY[fory + 1]){
temp = ADC_TEMP_ARRAY[fory];
ADC_TEMP_ARRAY[fory] = ADC_TEMP_ARRAY[fory + 1];
ADC_TEMP_ARRAY[fory + 1] = temp;
}
}
}
SET_ADC_VALUE(adc_select_chan,ADC_TEMP_ARRAY[2]);
if(adc_select_chan != AIN7){
adc_select_chan = AIN7;
ADC_SWITCH(adc_select_chan);
ADC_START();
}else{
INTERRUPT_INIT(ADC,0);
ADC_EN(0);
adc_finish_flag = 1;
}
}else{
ADC_START();
}
}
void INTERRUPT_BTM(void) interrupt 9{
PCON &= 0XFD;
}
void INTERRUPT_INT2(void) interrupt 10{
PWR_FUN_EN(0);
INTERRUPT_INIT(INT2,0);
INT2R &= 0XFE;
INT2F &= 0XFE;
sys_fun_error_flag = 1;
}
四,编程过程与心得:
1,现在公司最近开发的两个项目都是用赛元MCU并带有触摸模块,所以在此项目上添加官方触控库比较容易,具体方法请参阅官方相关文件。
2,在项目前期是打算用官方的低功耗触控库的,但因时间问题在实现官方给出的函数时,出现调用不是好顺利。所以将触控库中的触摸模块寄存器
提取出来,在触摸库检测不到用感应时去关闭触摸模块及其它模块电源,只留Base Time并设置为1S唤醒中断,再一次打触摸库电源。从而实际普通库成低功耗库的方法。
3,因为接近感应键的感应盘太长,很容易由其它微小的变化引起大的变化,在用触控调试软件来调触控键时,反复几个钟才调好水龙头静态接近感应参数。
4,当转换到动态测试中发现灵敏度及感应距离短等情况,由于提交项目时间问题,只能等到提交项目后才深入调试。
5,因SC92F8617这粒MCU资源较丰富,能很容易实现开发中小型项目。其它资源以后再深入了解应用。
余下内容请移步到《【赛元95F】——低功耗电容式接近触摸感应水龙头(三)》... https://bbs.21ic.com/icview-2940400-1-1.html?fromuser=szkeinew
|
共1人点赞
|