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

[复制链接]
2156|31
 楼主| chen915 发表于 2020-8-28 17:09 | 显示全部楼层 |阅读模式
新人首帖。使用stc单片机+adc按键+状态机消抖,程序能运行,但按键切换时间可达40多秒,不知道哪里出错。请走过路过帮看下啊,不胜感激

等会附上原理图部分,以及源码。
 楼主| chen915 发表于 2020-8-28 17:11 | 显示全部楼层
本帖最后由 chen915 于 2020-8-31 16:39 编辑
  1. #include "stc12c5630ad.h"

  2. typedef unsigned char u8 ;
  3. typedef unsigned int u16 ;

  4. #define buzz                 P32
  5. #define led                 P31
  6. #define adc_key         P11
  7. #define VCC                 5000

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

  16. void buzz_on(void)
  17. {
  18.         buzz = 1 ;
  19. }

  20. void buzz_off(void)
  21. {
  22.         buzz = 0 ;
  23. }

  24. void led_on(void)
  25. {
  26.         led = 0 ;
  27. }

  28. void led_off(void)
  29. {
  30.         led = 1 ;
  31. }

  32. void set_timer(u16 led_on_time_temp , u16 led_off_time_temp , VOID funtion1 , VOID funtion2)
  33. {        //3、第一个参数为LED点亮时长,第二位灭时长,三为亮函数,四为灭函数
  34.         led_on_time = led_on_time_temp ;
  35.         led_off_time = led_off_time_temp ;
  36.         
  37.         if(flag1 == 1)
  38.         {
  39.                 flag1 = 0 ;
  40.                 funtion_run = funtion1 ; //指针指向亮函数
  41.                 funtion_run() ;                  //并运行所指向的函数
  42.         }
  43.         if(flag2 == 1)
  44.         {
  45.                 flag2 = 0 ;
  46.                 funtion_run = funtion2 ; //指针指向灭函数
  47.                 funtion_run() ;                  //并运行所指向的函数
  48.         }
  49. }
  50. /*******************************************************************************************************************************/
  51. //P1M0 , P1M1 , ADC_CONTR=[ADC_POWER][SPEED1][SPEED0][ADC_FLAG]    [ADC_START][CHS2][CHS1][CHS0]
  52. //ADC_DATA , ADC_LOW2,AUXR=[T0x12][T1x12][UART_M0x12][EADCI][ESPI][ELVDI][-][-],IE,IP,IPH
  53. /*******************************************************************************************************************************/
  54. #define adc_power_on (ADC_CONTR |= 0x80)
  55. #define adc_power_off (ADC_CONTR &= 0x7f)

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

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

  60. enum key_number  //键值枚举声明
  61. {
  62.         key1 = 1 , key2 ,
  63.         key3 , key4 ,
  64.         key5 , key6 ,
  65.         key7 , key8 ,
  66.         key9 , key10  //代表未按下
  67. } ;

  68. enum key_statues //按键状态枚举,分别为初始状态,按下状态,确认按下状态,松手状态
  69. {
  70.         key_statues0 = 0 , //初始态
  71.         key_statues1 = 1 , //按下态
  72.         key_statues2 ,     //确认按下态
  73.         key_statues3 ,                 //松手态
  74. } ;
  75. /*****************************************
  76. *****************************************/
  77. /*****************************************
  78. *****************************************/
  79. /*****************************************
  80. *****************************************/
  81. void adc_init(void) //ADC初始化
  82. {
  83.         ADC_CONTR = 0x61 ;  //0110 0001 //关adc,270个周期转换一次,关标志位,关闭启动位,选择1通道
  84.         adc_power_on ;         //重开adc
  85.         adc_start_on ;         //开启转换
  86.         adc_flag_clear ; //清adc转换标志位
  87. }

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

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

  96.         return result ;
  97. }

  98. u16 adc_hex2dec(float value) //16进制电压值转10进制,单位为mV毫伏
  99. {
  100.         float value_dec ;
  101.         value_dec = (VCC * (value))/1024 ;        
  102.         
  103.         return (u16)value_dec ;
  104. }

  105. /*****************************************
  106. *  00 准双向io口                01 推挽输出
  107. *  10 高阻输入                  11 开漏
  108. *****************************************/
  109. void gpio_init()  //gpio初始化函数
  110. {
  111.         P1 = 0x02 ; //0000 0010
  112.         P1M0 = 0x02 ; //0000 0010   
  113.         P1M1 = 0x00 ; //0000 0000  设置按键为输入
  114.         
  115.         P3 = 0x06 ; //0000 0110
  116.         P3M0 = 0x00 ; //0000 0000  
  117.         P3M1 = 0x06 ; //0000 0110  设置蜂鸣器和LED为输出
  118. }

  119. /*****************************************
  120. *****************************************/
  121. u8 adc_key_value_process(u16 adc_value)  //通过adc值定义键值并返回..........该函数有问题,需要对adc电压值进行更好的处理
  122. {
  123.         u16 temp_adc_value = adc_value ; //中间变量
  124.         temp_adc_value /= 100 ; //对100求模,若是需要更高精度,可改100为更小值
  125.         
  126.         switch (temp_adc_value) //temp_adc_value精度存在严重问题,建议再用一个switch语句判断键值,使电压值转化为0-10的数字
  127.         {
  128.                 case 41 :         //按键1按下电压值为4100mV左右
  129.                         return 1 ;    //返回1
  130.                 case 35 :
  131.                         return 2 ;
  132.                 case 30 :
  133.                         return 3 ;
  134.                 case 25 :
  135.                         return 4 ;
  136.                 case 21 :
  137.                         return 5 ;
  138.                 case 15 :
  139.                         return 6 ;
  140.                 case 10 :
  141.                         return 7 ;
  142.                 case 5 :
  143.                         return 8 ;
  144.                 case 0 :
  145.                         return 9 ;
  146.                
  147.                 default :        //未按下,返回0
  148.                         return 0 ;
  149.         }

  150. /************************************************************************************************
  151. //                adc_value = adc_hex2dec(adc_result()) ;
  152. //                if((adc_value>=0) && (adc_value<=5000)) //若是有按键按下,则按键对号
  153. //                {
  154. //                        if(0 == adc_value)
  155. //                                return 9;
  156. //                        else if((adc_value <  723)  && (adc_value >  323))  //+-200mV
  157. //                                return 8;
  158. //                        else if((adc_value < 1254)  && (adc_value >  854))
  159. //                                return 7;
  160. //                        else if((adc_value < 1742)  && (adc_value > 1342))
  161. //                                return 6;
  162. //                        else if((adc_value < 2338)  && (adc_value > 1938))
  163. //                                return 5;
  164. //                        else if((adc_value < 2778)  && (adc_value > 2378))
  165. //                                return 4;
  166. //                        else if((adc_value < 3237)  && (adc_value > 2837))
  167. //                                return 3;
  168. //                        else if((adc_value < 3793)  && (adc_value > 3393))
  169. //                                return 2;
  170. //                        else if((adc_value < 4306)  && (adc_value > 3906))
  171. //                                return 1;
  172. ////                        else if((adc_value <= 5000)  && (adc_value > 4795-244))  //无按键按下
  173. ////                                return 10;
  174. //                }
  175. //                else         //出错,则返回0
  176. //                {
  177. //                        return 0 ;
  178. //                }
  179. **************************************************************************************************/
  180. }
  181. /*****************************************
  182. *****************************************/
  183. u8 key_scan(void) //状态机函数,返回状态机键值
  184. {
  185.                 static u8 key_statues = key_statues0 ; //相当于锁,函数运行前与运行完,都要置0
  186.                 static u8 adc_key_number_temp ;
  187.                 u8 key_return ;        

  188.                 adc_key_number_temp = adc_key_value_process(adc_hex2dec(adc_result())) ;//采集adc,并转化为键值
  189.                 key_number = adc_key_number_temp ;
  190.                 switch(key_statues)
  191.                 {
  192.                         case key_statues0 : //初始态,也相当于锁
  193.                         {
  194.                                 if(0 != key_number) //若是有按键按下,则迁移至状态1------有按键按下时,key_number不会为0
  195.                                 {
  196.                                         key_statues = key_statues1 ;
  197.                                 }
  198.                         }
  199.                         break ;
  200.                         
  201.                         case key_statues1 : //按下态
  202.                         {
  203.                                 if(0 == key_number)        //如果只是抖动,则返回状态0
  204.                                 {
  205.                                         key_statues = key_statues0 ;
  206.                                 }
  207.                                 
  208.                                 else
  209.                                 {
  210.                                         key_statues = key_statues2 ;  //若是确实有按下,则迁移到状态2
  211.                                         key_number_final = key_number ; //如果确实有按键按下,则保存先前的key_number值
  212. #if 0                                       
  213. //                                        switch (key_number)        //若是按下有效,则将代码段放在此处
  214. //                                        {
  215. //                                                case 9 :
  216. //                                                {
  217. //                                                        key_return = key9 ;
  218. //                                                }
  219. //                                                break ;
  220. //                                                
  221. //                                                case 8 :
  222. //                                                {
  223. //                                                        key_return = key8 ;
  224. //                                                }
  225. //                                                break ;
  226. //                                                
  227. //                                                case 7 :
  228. //                                                {
  229. //                                                        key_return = key7 ;
  230. //                                                }
  231. //                                                break ;
  232. //                                                
  233. //                                                case 6 :
  234. //                                                {
  235. //                                                        key_return = key6 ;
  236. //                                                }
  237. //                                                break ;
  238. //                                                
  239. //                                                case 5 :
  240. //                                                {
  241. //                                                        key_return = key5 ;
  242. //                                                }
  243. //                                                break ;
  244. //                                                
  245. //                                                case 4 :
  246. //                                                {
  247. //                                                        key_return = key4 ;
  248. //                                                }
  249. //                                                break ;
  250. //                                                
  251. //                                                case 3 :
  252. //                                                {
  253. //                                                        key_return = key3 ;
  254. //                                                }
  255. //                                                break ;
  256. //                                                
  257. //                                                case 2 :
  258. //                                                {
  259. //                                                        key_return = key2 ;
  260. //                                                }
  261. //                                                break ;
  262. //                                                
  263. //                                                case 1 :
  264. //                                                {
  265. //                                                        key_return = key1 ;
  266. //                                                }
  267. //                                                break ;
  268. //                                                
  269. ////                                                case 10 :        //该处移往松手态
  270. ////                                                {
  271. ////                                                        key_return = key10 ;        
  272. ////                                                }
  273. ////                                                break ;
  274. #endif
  275.                                 }
  276.                         }        
  277.                         break ;
  278.                         
  279.                         case key_statues2 : //确认按下态,确认按下之后就应该判断是否松手,并进行消抖
  280.                         {
  281.                                 if(0 == key_number)                //若已松手,迁移至状态3,相当于松手消抖
  282.                                         key_statues = key_statues3 ;
  283.                         }
  284.                         break ;
  285.                         
  286.                         case key_statues3 : //松手态
  287.                         {
  288.                                 if(0 == key_number) //确实已经松手
  289.                                 {        
  290.                                         key_statues = key_statues0 ; //如果是确认无按键按下,则将状态迁移回状态0,即初始态。相当于自锁
  291. //                                        key_return = key10 ;        //松手返回key10
  292.                                         adc_key_number_temp = 0 ;
  293.                                        
  294.                                         switch (key_number_final)        //松手后键值有效
  295.                                         {
  296.                                                 case 9 :
  297.                                                         key_return = key9 ;
  298.                                                         break ;
  299.                                                 
  300.                                                 case 8 :
  301.                                                         key_return = key8 ;
  302.                                                         break ;
  303.                                                 
  304.                                                 case 7 :
  305.                                                         key_return = key7 ;
  306.                                                         break ;
  307.                                                 
  308.                                                 case 6 :
  309.                                                         key_return = key6 ;
  310.                                                         break ;
  311.                                                 
  312.                                                 case 5 :
  313.                                                         key_return = key5 ;
  314.                                                         break ;
  315.                                                 
  316.                                                 case 4 :
  317.                                                         key_return = key4 ;
  318.                                                         break ;
  319.                                                 
  320.                                                 case 3 :
  321.                                                         key_return = key3 ;
  322.                                                         break ;
  323.                                                 
  324.                                                 case 2 :
  325.                                                         key_return = key2 ;
  326.                                                         break ;
  327.                                                 
  328.                                                 case 1 :
  329.                                                         key_return = key1 ;
  330.                                                         break ;
  331.                                                 
  332.                                                 case 0:
  333.                                                         key_return = key10 ;
  334.                                                         break ;
  335.                                         }
  336.                                 }
  337.                                 else
  338.                                 {
  339.                                         key_statues = key_statues2 ; //否则回到状态2,即再判断一次
  340.                                 }
  341.                         }
  342.                         break ;
  343.                 }
  344.         
  345.                 return key_return ;
  346. }

  347. void key_process(u8 key_return_number)
  348. {
  349. //        buzz_run(key_return_number) ;
  350. //  u8 i = 0 ;         
  351.         switch(key_return_number)
  352.         {
  353.                 case key1 :
  354.                         set_timer(20 , 20 , led_on , led_off) ;
  355.                         break ;
  356.                
  357.                 case key2 :
  358.                         set_timer(60 , 60 , led_on , led_off) ;
  359.                         break ;
  360.                
  361.                 case key3 :
  362.                         set_timer(200 , 200  , led_on , led_off) ;
  363.                         break ;
  364.                
  365.                 case key4 :
  366.                         set_timer(1000 , 1000  , led_on , led_off) ;
  367.                         break ;
  368.                
  369.                 case key5 :
  370.                         set_timer(2000 , 2000  , led_on , led_off) ;
  371.                         break ;
  372.                
  373.                 case key6 :
  374.                         set_timer(3000 , 3000  , led_on , led_off) ;
  375.                         break ;
  376.                
  377.                 case key7 :
  378.                         set_timer(4000 , 4000  , led_on , led_off) ;
  379.                         break ;
  380.                
  381.                 case key8 :
  382.                         set_timer(5000 , 5000  , led_on , led_off) ;
  383.                         break ;
  384.                
  385.                 case key9 :
  386.                         set_timer(6000 , 6000  , buzz_on , buzz_off) ;
  387.                         break ;
  388.         }
  389. }

  390. /*****************************************
  391. *****************************************/
  392. void timer0_init(void)  //定时器0初始化
  393. {
  394.         TMOD = 0x01 ;
  395.         TH0 = 0xfc ;  //1ms
  396.         TL0 = 0x66 ;
  397.         
  398.         ET0 = 1 ;
  399.         EA = 1 ;
  400.         
  401.         TR0 = 1 ;
  402. }
  403. /*****************************************
  404. *****************************************/
  405. void main()
  406. {
  407.         P31 = 1 ;
  408.         gpio_init() ;
  409.         timer0_init() ;
  410.         adc_init() ;
  411.         buzz = 0 ;
  412.         
  413. //        while(1)
  414. //                set_timer(6000 , 500 , led_on , led_off) ;
  415.         
  416.         while(1)
  417.         {        
  418.                 key_process(aaa) ;
  419.         }        
  420. }
  421. /*****************************************
  422. *****************************************/
  423. void timer0_interrupt(void) interrupt 1  //定时器0中断函数,1ms中断
  424. {
  425.         static u16 tt = 0 ;
  426.         
  427.         TH0 = 0xfc ;
  428.         TL0 = 0x66 ;
  429.         
  430.         tt++ ;
  431.         soft_timer_counter++ ;
  432.         if(tt == 10) //20ms进行一次扫描
  433.         {
  434.                 tt = 0 ;
  435.                 flag__key_scan = 1 ;
  436.                 aaa = key_scan() ;
  437.         }        
  438.         if(soft_timer_counter == (led_on_time+led_off_time)) //3、(led_on_time+led_off_time)是整个中断周期的时间,led_off_time在这里才现身
  439.                 soft_timer_counter = 0 ;         //清0        
  440.         if(soft_timer_counter < led_on_time)  //1、这两个if最为重要,若是小于,则置位flag1
  441.                 flag1 = 1 ;         
  442.         else        //2、否则,置位flag2,通过if和else组合,将一段时间一分为2,控制LED亮灭时间//注意,在此并未设置熄灭LED的时间长度,而是通过后面的led_off_time来控制
  443.                 flag2 = 1 ;
  444. }
 楼主| chen915 发表于 2020-8-28 17:13 | 显示全部楼层

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| chen915 发表于 2020-8-28 17:13 | 显示全部楼层

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| chen915 发表于 2020-8-29 10:18 | 显示全部楼层
本帖最后由 chen915 于 2020-8-31 17:06 编辑
  1. void key_process(u8 key_return_number)
  2. {   
  3.         switch(key_return_number)
  4.         {
  5.                 case key1 :
  6.                         set_timer(20 , 20 , led_on , led_off) ;
  7.                         break ;
  8.                
  9.                 case key2 :
  10.                         set_timer(60 , 60 , led_on , led_off) ;
  11.                         break ;
  12.                
  13.                 case key3 :
  14.                         set_timer(200 , 200  , led_on , led_off) ;
  15.                         break ;
  16.                
  17.                 case key4 :
  18.                         set_timer(1000 , 1000  , led_on , led_off) ;
  19.                         break ;
  20.                
  21.                 case key5 :
  22.                         set_timer(2000 , 2000  , led_on , led_off) ;
  23.                         break ;
  24.                
  25.                 case key6 :
  26.                         set_timer(3000 , 3000  , led_on , led_off) ;
  27.                         break ;
  28.                
  29.                 case key7 :
  30.                         set_timer(4000 , 4000  , led_on , led_off) ;
  31.                         break ;
  32.                
  33.                 case key8 :
  34.                         set_timer(5000 , 5000  , led_on , led_off) ;
  35.                         break ;
  36.                
  37.                 case key9 :
  38.                         set_timer(6000 , 6000  , buzz_on , buzz_off) ;
  39.                         break ;
  40.         }
  41. }


这是按键处理函数。LED闪烁频率逐渐放慢。。。。。。程序是能跑起来。存在问题是,由高频向低频(比如先按key1再按key6)切换,切换得很快。但是反过来,比如先按key6再按key1,中间切换的时长40秒左右
xyz549040622 发表于 2020-8-29 20:51 | 显示全部楼层
感觉像是具体算法的问题,建议跟踪键值处理函数看看。
ayb_ice 发表于 2020-8-31 14:07 | 显示全部楼层
chen915 发表于 2020-8-29 10:18
这是按键处理函数。LED闪烁频率逐渐放慢。。。。。。程序是能跑起来。存在问题是,由高频向低频(比如先 ...

key_scan函数每次返回的不是个确切的值,这里逻辑混乱

set_timer这个函数的参数也混乱,这个函数只在有按键时调用,但传入的函数led_on , led_off运行又取决于flag1,flag2,这等于撞大运,撞到就执行,撞不到就不执行,直到下一次按键时再撞大运
 楼主| chen915 发表于 2020-8-31 17:08 | 显示全部楼层
xyz549040622 发表于 2020-8-29 20:51
感觉像是具体算法的问题,建议跟踪键值处理函数看看。

好的。多谢
 楼主| chen915 发表于 2020-8-31 17:14 | 显示全部楼层
ayb_ice 发表于 2020-8-31 14:07
key_scan函数每次返回的不是个确切的值,这里逻辑混乱

set_timer这个函数的参数也混乱,这个函数只在有 ...

会执行,就是间隔时间非常长

而且从短时到长时的切换比较即时,比如set_timer(20 , 20 , led_on , led_off) ; 切换到set_timer(4000 , 4000  , led_on , led_off) ; 就很即时

但是反过来,就是等半分钟后才执行
比如set_timer(4000 , 4000  , led_on , led_off) ; 切换为set_timer(20 , 20 , led_on , led_off) ;就非常耗时,但也还是能运行
ayb_ice 发表于 2020-8-31 17:15 | 显示全部楼层
chen915 发表于 2020-8-31 17:14
会执行,就是间隔时间非常长

而且从短时到长时的切换比较即时,比如set_timer(20 , 20 , led_on , led_o ...

函数的调用逻辑有问题
 楼主| chen915 发表于 2020-9-1 15:25 | 显示全部楼层
ayb_ice 发表于 2020-8-31 17:15
函数的调用逻辑有问题

弄了一天,搞不定,反而原本的思路都更乱了。请问该怎么做?想让按键按下,就让某个函数跑传入的时间段。就这样而已
ayb_ice 发表于 2020-9-1 15:31 | 显示全部楼层
chen915 发表于 2020-9-1 15:25
弄了一天,搞不定,反而原本的思路都更乱了。请问该怎么做?想让按键按下,就让某个函数跑传入的时间段。 ...

flag1 = 1 ; 改成开LED,
flag1 = 2 ; 改成关LED,
set_timer(6000 , 6000  , buzz_on , buzz_off) ; 改为set_timer(6000 , 6000) ; 不就可以了吗

u8 key_return ;改为 u8 key_return = 0;
 楼主| chen915 发表于 2020-9-1 16:18 | 显示全部楼层
ayb_ice 发表于 2020-9-1 15:31
flag1 = 1 ; 改成开LED,
flag1 = 2 ; 改成关LED,
set_timer(6000 , 6000  , buzz_on , buzz_off) ; 改 ...
  1. #include "stc12c5630ad.h"

  2. typedef unsigned char u8 ;
  3. typedef unsigned int u16 ;

  4. #define buzz                 P32
  5. #define led                 P31
  6. #define adc_key         P11
  7. #define VCC                 5000

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

  16. //void buzz_on(void)
  17. //{
  18. //        buzz = 1 ;
  19. //}

  20. //void buzz_off(void)
  21. //{
  22. //        buzz = 0 ;
  23. //}

  24. void led_on(void)
  25. {
  26.         led = 0 ;
  27. }

  28. void led_off(void)
  29. {
  30.         led = 1 ;
  31. }

  32. void set_timer(u16 led_on_time_temp , u16 led_off_time_temp)
  33. {        //3、第一个参数为LED点亮时长,第二位灭时长
  34.         led_on_time = led_on_time_temp ;
  35.         led_off_time = led_off_time_temp ;
  36. }
  37. /*******************************************************************************************************************************/
  38. //P1M0 , P1M1 , ADC_CONTR=[ADC_POWER][SPEED1][SPEED0][ADC_FLAG]    [ADC_START][CHS2][CHS1][CHS0]
  39. //ADC_DATA , ADC_LOW2,AUXR=[T0x12][T1x12][UART_M0x12][EADCI][ESPI][ELVDI][-][-],IE,IP,IPH
  40. /*******************************************************************************************************************************/
  41. #define adc_power_on (ADC_CONTR |= 0x80)
  42. #define adc_power_off (ADC_CONTR &= 0x7f)

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

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

  47. enum key_number  //键值枚举声明
  48. {
  49.         key1 = 1 , key2 ,
  50.         key3 , key4 ,
  51.         key5 , key6 ,
  52.         key7 , key8 ,
  53.         key9 , key10  //代表未按下
  54. } ;

  55. enum key_statues //按键状态枚举,分别为初始状态,按下状态,确认按下状态,松手状态
  56. {
  57.         key_statues0 = 0 , //初始态
  58.         key_statues1 = 1 , //按下态
  59.         key_statues2 ,     //确认按下态
  60.         key_statues3 ,                 //松手态
  61. } ;
  62. /*****************************************
  63. *****************************************/
  64. void adc_init(void) //ADC初始化
  65. {
  66.         ADC_CONTR = 0x61 ;  //0110 0001 //关adc,270个周期转换一次,关标志位,关闭启动位,选择1通道
  67.         adc_power_on ;         //重开adc
  68.         adc_start_on ;         //开启转换
  69.         adc_flag_clear ; //清adc转换标志位
  70. }

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

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

  79.         return result ;
  80. }

  81. u16 adc_hex2dec(float value) //16进制电压值转10进制,单位为mV毫伏
  82. {
  83.         float value_dec ;
  84.         value_dec = (VCC * (value))/1024 ;        
  85.         
  86.         return (u16)value_dec ;
  87. }

  88. /*****************************************
  89. *  00 准双向io口                01 推挽输出
  90. *  10 高阻输入                  11 开漏
  91. *****************************************/
  92. void gpio_init()  //gpio初始化函数
  93. {
  94.         P1 = 0x02 ; //0000 0010
  95.         P1M0 = 0x02 ; //0000 0010   
  96.         P1M1 = 0x00 ; //0000 0000  设置按键为输入
  97.         
  98.         P3 = 0x06 ; //0000 0110
  99.         P3M0 = 0x00 ; //0000 0000  
  100.         P3M1 = 0x06 ; //0000 0110  设置蜂鸣器和LED为输出
  101. }

  102. /*****************************************
  103. *****************************************/
  104. u8 adc_key_value_process(u16 adc_value)  //通过adc值定义键值并返回..........该函数有问题,需要对adc电压值进行更好的处理
  105. {
  106.         u16 temp_adc_value = adc_value ; //中间变量
  107.         temp_adc_value /= 100 ; //对100求模,若是需要更高精度,可改100为更小值
  108.         
  109.         switch (temp_adc_value) //temp_adc_value精度存在严重问题,建议再用一个switch语句判断键值,使电压值转化为0-10的数字
  110.         {
  111.                 case 41 :         //按键1按下电压值为4100mV左右
  112.                         return 1 ;    //返回1
  113.                 case 35 :
  114.                         return 2 ;
  115.                 case 30 :
  116.                         return 3 ;
  117.                 case 25 :
  118.                         return 4 ;
  119.                 case 21 :
  120.                         return 5 ;
  121.                 case 15 :
  122.                         return 6 ;
  123.                 case 10 :
  124.                         return 7 ;
  125.                 case 5 :
  126.                         return 8 ;
  127.                 case 0 :
  128.                         return 9 ;
  129.                
  130.                 default :        //未按下,返回0
  131.                         return 0 ;
  132.         }
  133. }
  134. /*****************************************
  135. *****************************************/
  136. u8 key_scan(void) //状态机函数,返回状态机键值
  137. {
  138.                 static u8 key_statues = key_statues0 ; //相当于锁,函数运行前与运行完,都要置0
  139.                 static u8 adc_key_number_temp ;
  140.                 u8 key_return = 0 ;        

  141.                 adc_key_number_temp = adc_key_value_process(adc_hex2dec(adc_result())) ;//采集adc,并转化为键值
  142.                 key_number = adc_key_number_temp ;
  143.                 switch(key_statues)
  144.                 {
  145.                         case key_statues0 : //初始态,也相当于锁
  146.                         {
  147.                                 if(0 != key_number) //若是有按键按下,则迁移至状态1------有按键按下时,key_number不会为0
  148.                                 {
  149.                                         key_statues = key_statues1 ;
  150.                                 }
  151.                         }
  152.                         break ;
  153.                         
  154.                         case key_statues1 : //按下态
  155.                         {
  156.                                 if(0 == key_number)        //如果只是抖动,则返回状态0
  157.                                 {
  158.                                         key_statues = key_statues0 ;
  159.                                 }
  160.                                 
  161.                                 else
  162.                                 {
  163.                                         key_statues = key_statues2 ;  //若是确实有按下,则迁移到状态2
  164.                                         key_number_final = key_number ; //如果确实有按键按下,则保存先前的key_number值
  165.                                 }
  166.                         }        
  167.                         break ;
  168.                         
  169.                         case key_statues2 : //确认按下态,确认按下之后就应该判断是否松手,并进行消抖
  170.                         {
  171.                                 if(0 == key_number)                //若已松手,迁移至状态3,相当于松手消抖
  172.                                         key_statues = key_statues3 ;
  173.                         }
  174.                         break ;
  175.                         
  176.                         case key_statues3 : //松手态
  177.                         {
  178.                                 if(0 == key_number) //确实已经松手
  179.                                 {        
  180.                                         key_statues = key_statues0 ; //如果是确认无按键按下,则将状态迁移回状态0,即初始态。相当于自锁
  181.                                         adc_key_number_temp = 0 ;
  182.                                        
  183.                                         switch (key_number_final)        //松手后键值有效
  184.                                         {
  185.                                                 case 9 :
  186.                                                         key_return = key9 ;
  187.                                                         break ;
  188.                                                 
  189.                                                 case 8 :
  190.                                                         key_return = key8 ;
  191.                                                         break ;
  192.                                                 
  193.                                                 case 7 :
  194.                                                         key_return = key7 ;
  195.                                                         break ;
  196.                                                 
  197.                                                 case 6 :
  198.                                                         key_return = key6 ;
  199.                                                         break ;
  200.                                                 
  201.                                                 case 5 :
  202.                                                         key_return = key5 ;
  203.                                                         break ;
  204.                                                 
  205.                                                 case 4 :
  206.                                                         key_return = key4 ;
  207.                                                         break ;
  208.                                                 
  209.                                                 case 3 :
  210.                                                         key_return = key3 ;
  211.                                                         break ;
  212.                                                 
  213.                                                 case 2 :
  214.                                                         key_return = key2 ;
  215.                                                         break ;
  216.                                                 
  217.                                                 case 1 :
  218.                                                         key_return = key1 ;
  219.                                                         break ;
  220.                                                 
  221.                                                 case 0:
  222.                                                         key_return = key10 ;
  223.                                                         break ;
  224.                                         }
  225.                                 }
  226.                                 else
  227.                                 {
  228.                                         key_statues = key_statues2 ; //否则回到状态2,即再判断一次
  229.                                 }
  230.                         }
  231.                         break ;
  232.                 }
  233.         
  234.                 return key_return ;
  235. }

  236. void key_process(u8 key_return_number)
  237. {      
  238.         switch(key_return_number)
  239.         {
  240.                 case key1 :
  241. //                        set_timer(20 , 20 , led_on , led_off) ;
  242.                                                 set_timer(20 , 20) ;
  243.                         break ;
  244.                
  245.                 case key2 :
  246. //                        set_timer(60 , 60 , led_on , led_off) ;
  247.                                                 set_timer(60 , 60) ;
  248.                         break ;
  249.                
  250.                 case key3 :
  251. //                        set_timer(200 , 200  , led_on , led_off) ;
  252.                                         set_timer(200 , 200) ;
  253.                         break ;
  254.                
  255.                 case key4 :
  256. //                        set_timer(1000 , 1000  , led_on , led_off) ;
  257.                                                 set_timer(1000 , 1000) ;
  258.                         break ;
  259.                
  260.                 case key5 :
  261. //                        set_timer(2000 , 2000  , led_on , led_off) ;
  262.                                                 set_timer(2000 , 2000) ;
  263.                         break ;
  264.                
  265.                 case key6 :
  266. //                        set_timer(3000 , 3000  , led_on , led_off) ;
  267.                                                 set_timer(3000 , 3000) ;
  268.                         break ;
  269.                
  270.                 case key7 :
  271. //                        set_timer(4000 , 4000  , led_on , led_off) ;
  272.                                                 set_timer(4000 , 4000) ;
  273.                         break ;
  274.                
  275.                 case key8 :
  276. //                        set_timer(5000 , 5000  , led_on , led_off) ;
  277.                                                 set_timer(5000 , 5000) ;
  278.                         break ;
  279.                
  280.                 case key9 :
  281. //                        set_timer(6000 , 6000  , buzz_on , buzz_off) ;
  282.                                                 set_timer(6000 , 6000) ;
  283.                         break ;
  284.         }
  285. }

  286. /*****************************************
  287. *****************************************/
  288. void timer0_init(void)  //定时器0初始化
  289. {
  290.         TMOD = 0x01 ;
  291.         TH0 = 0xfc ;  //1ms
  292.         TL0 = 0x66 ;
  293.         
  294.         ET0 = 1 ;
  295.         EA = 1 ;
  296.         
  297.         TR0 = 1 ;
  298. }
  299. /*****************************************
  300. *****************************************/
  301. void main()
  302. {
  303.         P31 = 1 ;
  304.         gpio_init() ;
  305.         timer0_init() ;
  306.         adc_init() ;
  307.         buzz = 0 ;

  308.         while(1)
  309.         {        
  310.                 key_process(aaa) ;
  311.         }        
  312. }
  313. /*****************************************
  314. *****************************************/
  315. void timer0_interrupt(void) interrupt 1  //定时器0中断函数,1ms中断
  316. {
  317.         static u16 tt = 0 ;
  318.         
  319.         TH0 = 0xfc ;
  320.         TL0 = 0x66 ;
  321.         
  322.         tt++ ;
  323.         soft_timer_counter++ ;
  324.         if(tt == 10) //10ms进行一次扫描
  325.         {
  326.                 tt = 0 ;
  327.                 flag__key_scan = 1 ;
  328.                 aaa = key_scan() ;
  329.         }        
  330.         if(soft_timer_counter == (led_on_time+led_off_time))
  331.                 soft_timer_counter = 0 ;         //清0   
  332.             if(soft_timer_counter < led_on_time)  
  333.                 {
  334.                 funtion_run = led_on ; //指针指向亮函数
  335.                 funtion_run() ;                  //并运行所指向的函数   
  336.                 }                       
  337.         else        
  338.         {
  339.                                 funtion_run = led_off ; //指针指向灭函数
  340.                 funtion_run() ;  //运行之
  341.                 }               

  342. }


现在改成这样也一样,切换很耗时。按键处理感觉不存在问题啊
ayb_ice 发表于 2020-9-1 16:33 | 显示全部楼层
chen915 发表于 2020-9-1 16:18
现在改成这样也一样,切换很耗时。按键处理感觉不存在问题啊

这个地方改下
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))
        {
                soft_timer_counter = 0 ;         //清0   
        }
        if(soft_timer_counter < led_on_time)  
        {
                funtion_run = led_on ; //指针指向亮函数
                funtion_run() ;                  //并运行所指向的函数   
        }                        
        else        
        {
                funtion_run = led_off ; //指针指向灭函数
                funtion_run() ;  //运行之
        }               

}
 楼主| chen915 发表于 2020-9-1 17:02 | 显示全部楼层
ayb_ice 发表于 2020-9-1 16:33
这个地方改下
void timer0_interrupt(void) interrupt 1  //定时器0中断函数,1ms中断
{

我也觉得是中断用两个变量tt和soft_timer_counter操作有问题,并且两者毫无关系,容易冲突。正在试
character 发表于 2020-9-2 08:25 | 显示全部楼层
 楼主| chen915 发表于 2020-9-3 11:20 | 显示全部楼层
chen915 发表于 2020-9-1 17:02
我也觉得是中断用两个变量tt和soft_timer_counter操作有问题,并且两者毫无关系,容易冲突。正在试 ...

还是不行。是不是状态机不好应用在adc按键上啊
ayb_ice 发表于 2020-9-3 11:31 | 显示全部楼层
chen915 发表于 2020-9-3 11:20
还是不行。是不是状态机不好应用在adc按键上啊

你这可能是按键扫描有问题,先屏蔽后测试下,一段时间后自动模拟下按键变化,测试下其它代码有问题吗
 楼主| chen915 发表于 2020-9-8 19:01 | 显示全部楼层
ayb_ice 发表于 2020-9-3 11:31
你这可能是按键扫描有问题,先屏蔽后测试下,一段时间后自动模拟下按键变化,测试下其它代码有问题吗 ...



还是不行,请问还有其他的方法消抖吗?
ayb_ice 发表于 2020-9-9 08:30 | 显示全部楼层
chen915 发表于 2020-9-8 19:01
还是不行,请问还有其他的方法消抖吗?

定时去读按键,相邻的两次有变化(不是按下就是松开)就可以了,按键对定时也不敏感10~100MS均可
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

50

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部