发新帖我要提问
12
返回列表
打印

stc+adc按键+状态机,程序能运行,但按键切换时间可达40多秒,不知道哪里出错

[复制链接]
楼主: chen915
手机看帖
扫描二维码
随时随地手机跟帖
21
chen915|  楼主 | 2020-9-11 11:44 | 只看该作者 回帖奖励 |倒序浏览
ayb_ice 发表于 2020-9-9 08:30
定时去读按键,相邻的两次有变化(不是按下就是松开)就可以了,按键对定时也不敏感10~100MS均可 ...

多谢

使用特权

评论回复
22
chen915|  楼主 | 2020-9-11 11:50 | 只看该作者
/*******原程序**********/
#include "stc12c5630ad.h"

typedef unsigned char u8 ;
typedef unsigned int u16 ;

#define buzz                 P32
#define led                 P31
#define adc_key         P11
#define VCC                 5000

u8 aaa = 0 ;
u8 flag__key_scan ;
u8 key_number ;
u8 key_number_final ;
unsigned char flag1 , flag2 ;  //两个软定时标志位,前者为LED亮的时间段,后者为灭
unsigned int soft_timer_counter  , led_on_time , led_off_time ; //软定时自增变量,led亮时间,LED灭时间
typedef void (*VOID)(void) ;  //先定义函数指针
VOID funtion_run ;

void buzz_on(void)
{
        buzz = 1 ;
}

void buzz_off(void)
{
        buzz = 0 ;
}

void led_on(void)
{
        led = 0 ;
}

void led_off(void)
{
        led = 1 ;
}

void set_timer(u16 led_on_time_temp , u16 led_off_time_temp , VOID funtion1 , VOID funtion2)
{        //3、第一个参数为LED点亮时长,第二位灭时长,三为亮函数,四为灭函数
        led_on_time = led_on_time_temp ;
        led_off_time = led_off_time_temp ;
        
        if(flag1 == 1)
        {
                flag1 = 0 ;
                funtion_run = funtion1 ; //指针指向亮函数
                funtion_run() ;                  //并运行所指向的函数
        }
        if(flag2 == 1)
        {
                flag2 = 0 ;
                funtion_run = funtion2 ; //指针指向灭函数
                funtion_run() ;                  //并运行所指向的函数
        }
}
/*******************************************************************************************************************************/
//P1M0 , P1M1 , ADC_CONTR=[ADC_POWER][SPEED1][SPEED0][ADC_FLAG]    [ADC_START][CHS2][CHS1][CHS0]
//ADC_DATA , ADC_LOW2,AUXR=[T0x12][T1x12][UART_M0x12][EADCI][ESPI][ELVDI][-][-],IE,IP,IPH
/*******************************************************************************************************************************/
#define adc_power_on (ADC_CONTR |= 0x80)
#define adc_power_off (ADC_CONTR &= 0x7f)

#define adc_flag_set (ADC_CONTR |= 0x10)
#define adc_flag_clear (ADC_CONTR &= 0xef)

#define adc_start_on (ADC_CONTR |= 0x08)
#define adc_start_off (ADC_CONTR &= 0xf7)

enum key_number  //键值枚举声明
{
        key1 = 1 , key2 ,
        key3 , key4 ,
        key5 , key6 ,
        key7 , key8 ,
        key9 , key10  //代表未按下
} ;

enum key_statues //按键状态枚举,分别为初始状态,按下状态,确认按下状态,松手状态
{
        key_statues0 = 0 , //初始态
        key_statues1 = 1 , //按下态
        key_statues2 ,     //确认按下态
        key_statues3 ,                 //松手态
} ;
/*****************************************
*****************************************/
/*****************************************
*****************************************/
/*****************************************
*****************************************/
void adc_init(void) //ADC初始化
{
        ADC_CONTR = 0x61 ;  //0110 0001 //关adc,270个周期转换一次,关标志位,关闭启动位,选择1通道
        adc_power_on ;         //重开adc
        adc_start_on ;         //开启转换
        adc_flag_clear ; //清adc转换标志位
}

u16 adc_result()  //获取ADC值
{
        u16 result = 0 ; //32bit数据装载10bit的adc转换结果值
        u16 value = 0  ;
        adc_init() ;         

        while(!(ADC_CONTR & 0x10)) ;  //& 0001 0000,若是完成转换,则bit5为1,与上0x10,仍为1,再取反为0,则跳过改行执行下一行
        result = ADC_DATA*4 + ADC_LOW2 ; //ADC_DATA寄存器为8bit,左移两位,再加上ADC_LOW2的值,即可得到转换后完整的10bit结果
        adc_flag_clear ; //清除ADC_FLAG标志位

        return result ;
}

u16 adc_hex2dec(float value) //16进制电压值转10进制,单位为mV毫伏
{
        float value_dec ;
        value_dec = (VCC * (value))/1024 ;        
        
        return (u16)value_dec ;
}

/*****************************************
*  00 准双向io口                01 推挽输出
*  10 高阻输入                  11 开漏
*****************************************/
void gpio_init()  //gpio初始化函数
{
        P1 = 0x02 ; //0000 0010
        P1M0 = 0x02 ; //0000 0010   
        P1M1 = 0x00 ; //0000 0000  设置按键为输入
        
        P3 = 0x06 ; //0000 0110
        P3M0 = 0x00 ; //0000 0000  
        P3M1 = 0x06 ; //0000 0110  设置蜂鸣器和LED为输出
}

/*****************************************
*****************************************/
u8 adc_key_value_process(u16 adc_value)  //通过adc值定义键值并返回..........该函数有问题,需要对adc电压值进行更好的处理
{
        u16 temp_adc_value = adc_value ; //中间变量
        temp_adc_value /= 100 ; //对100求模,若是需要更高精度,可改100为更小值
        
        switch (temp_adc_value) //temp_adc_value精度存在严重问题,建议再用一个switch语句判断键值,使电压值转化为0-10的数字
        {
                case 41 :         //按键1按下电压值为4100mV左右
                        return 1 ;    //返回1
                case 35 :
                        return 2 ;
                case 30 :
                        return 3 ;
                case 25 :
                        return 4 ;
                case 21 :
                        return 5 ;
                case 15 :
                        return 6 ;
                case 10 :
                        return 7 ;
                case 5 :
                        return 8 ;
                case 0 :
                        return 9 ;
               
                default :        //未按下,返回0
                        return 0 ;
        }

/************************************************************************************************
//                adc_value = adc_hex2dec(adc_result()) ;
//                if((adc_value>=0) && (adc_value<=5000)) //若是有按键按下,则按键对号
//                {
//                        if(0 == adc_value)
//                                return 9;
//                        else if((adc_value <  723)  && (adc_value >  323))  //+-200mV
//                                return 8;
//                        else if((adc_value < 1254)  && (adc_value >  854))
//                                return 7;
//                        else if((adc_value < 1742)  && (adc_value > 1342))
//                                return 6;
//                        else if((adc_value < 2338)  && (adc_value > 1938))
//                                return 5;
//                        else if((adc_value < 2778)  && (adc_value > 2378))
//                                return 4;
//                        else if((adc_value < 3237)  && (adc_value > 2837))
//                                return 3;
//                        else if((adc_value < 3793)  && (adc_value > 3393))
//                                return 2;
//                        else if((adc_value < 4306)  && (adc_value > 3906))
//                                return 1;
////                        else if((adc_value <= 5000)  && (adc_value > 4795-244))  //无按键按下
////                                return 10;
//                }
//                else         //出错,则返回0
//                {
//                        return 0 ;
//                }
**************************************************************************************************/
}
/*****************************************
*****************************************/
u8 key_scan(void) //状态机函数,返回状态机键值
{
                static u8 key_statues = key_statues0 ; //相当于锁,函数运行前与运行完,都要置0
                static u8 adc_key_number_temp ;
                u8 key_return ;        

                adc_key_number_temp = adc_key_value_process(adc_hex2dec(adc_result())) ;//采集adc,并转化为键值
                key_number = adc_key_number_temp ;
                switch(key_statues)
                {
                        case key_statues0 : //初始态,也相当于锁
                        {
                                if(0 != key_number) //若是有按键按下,则迁移至状态1------有按键按下时,key_number不会为0
                                {
                                        key_statues = key_statues1 ;
                                }
                        }
                        break ;
                        
                        case key_statues1 : //按下态
                        {
                                if(0 == key_number)        //如果只是抖动,则返回状态0
                                {
                                        key_statues = key_statues0 ;
                                }
                                
                                else
                                {
                                        key_statues = key_statues2 ;  //若是确实有按下,则迁移到状态2
                                        key_number_final = key_number ; //如果确实有按键按下,则保存先前的key_number值
#if 0                                       
//                                        switch (key_number)        //若是按下有效,则将代码段放在此处
//                                        {
//                                                case 9 :
//                                                {
//                                                        key_return = key9 ;
//                                                }
//                                                break ;
//                                                
//                                                case 8 :
//                                                {
//                                                        key_return = key8 ;
//                                                }
//                                                break ;
//                                                
//                                                case 7 :
//                                                {
//                                                        key_return = key7 ;
//                                                }
//                                                break ;
//                                                
//                                                case 6 :
//                                                {
//                                                        key_return = key6 ;
//                                                }
//                                                break ;
//                                                
//                                                case 5 :
//                                                {
//                                                        key_return = key5 ;
//                                                }
//                                                break ;
//                                                
//                                                case 4 :
//                                                {
//                                                        key_return = key4 ;
//                                                }
//                                                break ;
//                                                
//                                                case 3 :
//                                                {
//                                                        key_return = key3 ;
//                                                }
//                                                break ;
//                                                
//                                                case 2 :
//                                                {
//                                                        key_return = key2 ;
//                                                }
//                                                break ;
//                                                
//                                                case 1 :
//                                                {
//                                                        key_return = key1 ;
//                                                }
//                                                break ;
//                                                
////                                                case 10 :        //该处移往松手态
////                                                {
////                                                        key_return = key10 ;        
////                                                }
////                                                break ;
#endif
                                }
                        }        
                        break ;
                        
                        case key_statues2 : //确认按下态,确认按下之后就应该判断是否松手,并进行消抖
                        {
                                if(0 == key_number)                //若已松手,迁移至状态3,相当于松手消抖
                                        key_statues = key_statues3 ;
                        }
                        break ;
                        
                        case key_statues3 : //松手态
                        {
                                if(0 == key_number) //确实已经松手
                                {        
                                        key_statues = key_statues0 ; //如果是确认无按键按下,则将状态迁移回状态0,即初始态。相当于自锁
//                                        key_return = key10 ;        //松手返回key10
                                        adc_key_number_temp = 0 ;
                                       
                                        switch (key_number_final)        //松手后键值有效
                                        {
                                                case 9 :
                                                        key_return = key9 ;
                                                        break ;
                                                
                                                case 8 :
                                                        key_return = key8 ;
                                                        break ;
                                                
                                                case 7 :
                                                        key_return = key7 ;
                                                        break ;
                                                
                                                case 6 :
                                                        key_return = key6 ;
                                                        break ;
                                                
                                                case 5 :
                                                        key_return = key5 ;
                                                        break ;
                                                
                                                case 4 :
                                                        key_return = key4 ;
                                                        break ;
                                                
                                                case 3 :
                                                        key_return = key3 ;
                                                        break ;
                                                
                                                case 2 :
                                                        key_return = key2 ;
                                                        break ;
                                                
                                                case 1 :
                                                        key_return = key1 ;
                                                        break ;
                                                
                                                case 0:
                                                        key_return = key10 ;
                                                        break ;
                                        }
                                }
                                else
                                {
                                        key_statues = key_statues2 ; //否则回到状态2,即再判断一次
                                }
                        }
                        break ;
                }
        
                return key_return ;
}

void key_process(u8 key_return_number)
{
//        buzz_run(key_return_number) ;
//  u8 i = 0 ;         
        switch(key_return_number)
        {
                case key1 :
                        set_timer(20 , 20 , led_on , led_off) ;
                        break ;
               
                case key2 :
                        set_timer(60 , 60 , led_on , led_off) ;
                        break ;
               
                case key3 :
                        set_timer(200 , 200  , led_on , led_off) ;
                        break ;
               
                case key4 :
                        set_timer(1000 , 1000  , led_on , led_off) ;
                        break ;
               
                case key5 :
                        set_timer(2000 , 2000  , led_on , led_off) ;
                        break ;
               
                case key6 :
                        set_timer(3000 , 3000  , led_on , led_off) ;
                        break ;
               
                case key7 :
                        set_timer(4000 , 4000  , led_on , led_off) ;
                        break ;
               
                case key8 :
                        set_timer(5000 , 5000  , led_on , led_off) ;
                        break ;
               
                case key9 :
                        set_timer(6000 , 6000  , buzz_on , buzz_off) ;
                        break ;
        }
}

/*****************************************
*****************************************/
void timer0_init(void)  //定时器0初始化
{
        TMOD = 0x01 ;
        TH0 = 0xfc ;  //1ms
        TL0 = 0x66 ;
        
        ET0 = 1 ;
        EA = 1 ;
        
        TR0 = 1 ;
}
/*****************************************
*****************************************/
void main()
{
        P31 = 1 ;
        gpio_init() ;
        timer0_init() ;
        adc_init() ;
        buzz = 0 ;
        
//        while(1)
//                set_timer(6000 , 500 , led_on , led_off) ;
        
        while(1)
        {        
                key_process(aaa) ;
        }        
}
/*****************************************
*****************************************/
void timer0_interrupt(void) interrupt 1  //定时器0中断函数,1ms中断
{
        static u16 tt = 0 ;
        
        TH0 = 0xfc ;
        TL0 = 0x66 ;
        
        tt++ ;
        soft_timer_counter++ ;
        if(tt == 10) //10ms进行一次扫描
        {
                tt = 0 ;
                flag__key_scan = 1 ;
                aaa = key_scan() ;
        }        
        if(soft_timer_counter >= (led_on_time+led_off_time)) //3、(led_on_time+led_off_time)是整个中断周期的时间,led_off_time在这里才现身
                soft_timer_counter = 0 ;         //清0        
        if(soft_timer_counter < led_on_time)  //1、这两个if最为重要,若是小于,则置位flag1
                flag1 = 1 ;         
        else        //2、否则,置位flag2,通过if和else组合,将一段时间一分为2,控制LED亮灭时间//注意,在此并未设置熄灭LED的时间长度,而是通过后面的led_off_time来控制
                flag2 = 1 ;
}











结贴!!!!!!只改一条语句。。改if(soft_timer_counter == (led_on_time+led_off_time))为if(soft_timer_counter >= (led_on_time+led_off_time))。。。。。。。多谢各位耐心解答,谢谢!

使用特权

评论回复
23
chen915|  楼主 | 2020-9-11 11:58 | 只看该作者

后续~~~~~~~~~~~~~~~~~~~~
为什么不能用 == 呢?
是因为一条C语言代码可能要运行好几条汇编代码,而导致的误差吗?

使用特权

评论回复
24
ayb_ice| | 2020-9-11 14:45 | 只看该作者

这条代码我早就给你改过了,你没仔细看

使用特权

评论回复
25
chen915|  楼主 | 2020-9-11 15:53 | 只看该作者
ayb_ice 发表于 2020-9-11 14:45
这条代码我早就给你改过了,你没仔细看

好吧。当时只注意了标志位那部分,没全部复制粘贴。多谢。以后请多多支持啊。多谢

使用特权

评论回复
26
andy520520| | 2020-9-12 10:50 | 只看该作者

印象中C51不支持3个以上的形参吧?

使用特权

评论回复
27
雪山飞狐D| | 2020-9-12 14:38 | 只看该作者
      设置一个全局最高优先级的定时器10ms , 做各种低紧急的查询任务,每隔10ms 查询一次按键状态,设置一个按键缓冲内存,三次按键都被按下说明没有抖动,这时才确定按键,这样做理论上不会有大冲突和延迟

使用特权

评论回复
28
chen915|  楼主 | 2020-9-13 22:27 | 只看该作者
雪山飞狐D 发表于 2020-9-12 14:38
设置一个全局最高优先级的定时器10ms , 做各种低紧急的查询任务,每隔10ms 查询一次按键状态,设置一 ...

嗯。谢谢。要是有代码就更好了现在的理解能力还离不开代码

使用特权

评论回复
29
chen915|  楼主 | 2020-9-13 22:27 | 只看该作者
andy520520 发表于 2020-9-12 10:50
印象中C51不支持3个以上的形参吧?

要怎样处理好一点?

使用特权

评论回复
30
雪山飞狐D| | 2020-9-14 05:35 | 只看该作者
chen915 发表于 2020-9-13 22:27
嗯。谢谢。要是有代码就更好了现在的理解能力还离不开代码

https://bbs.21ic.com/icview-2525970-1-1.html
我以前写的

使用特权

评论回复
31
chen915|  楼主 | 2020-9-14 08:43 | 只看该作者
雪山飞狐D 发表于 2020-9-14 05:35
https://bbs.21ic.com/icview-2525970-1-1.html
我以前写的

学习了,谢谢

使用特权

评论回复
32
ayb_ice| | 2020-9-14 09:11 | 只看该作者
andy520520 发表于 2020-9-12 10:50
印象中C51不支持3个以上的形参吧?

不是这样的,通过寄存器最多可以传递4个参数(取决于参数类型大小),其它参数通过固定内存传送,并没有什么限制

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则