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

[复制链接]
2176|31
 楼主| chen915 发表于 2020-9-11 11:44 | 显示全部楼层
ayb_ice 发表于 2020-9-9 08:30
定时去读按键,相邻的两次有变化(不是按下就是松开)就可以了,按键对定时也不敏感10~100MS均可 ...

多谢
 楼主| chen915 发表于 2020-9-11 11:50 | 显示全部楼层
  1. /*******原程序**********/
  2. #include "stc12c5630ad.h"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  97.         return result ;
  98. }

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

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

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

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

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

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

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











  446. 结贴!!!!!!只改一条语句。。改if(soft_timer_counter == (led_on_time+led_off_time))为if(soft_timer_counter >= (led_on_time+led_off_time))。。。。。。。多谢各位耐心解答,谢谢!
 楼主| chen915 发表于 2020-9-11 11:58 | 显示全部楼层

后续~~~~~~~~~~~~~~~~~~~~
为什么不能用 == 呢?
是因为一条C语言代码可能要运行好几条汇编代码,而导致的误差吗?
ayb_ice 发表于 2020-9-11 14:45 | 显示全部楼层

这条代码我早就给你改过了,你没仔细看
 楼主| chen915 发表于 2020-9-11 15:53 | 显示全部楼层
ayb_ice 发表于 2020-9-11 14:45
这条代码我早就给你改过了,你没仔细看

好吧。当时只注意了标志位那部分,没全部复制粘贴。多谢。以后请多多支持啊。多谢
andy520520 发表于 2020-9-12 10:50 | 显示全部楼层

印象中C51不支持3个以上的形参吧?
雪山飞狐D 发表于 2020-9-12 14:38 | 显示全部楼层
      设置一个全局最高优先级的定时器10ms , 做各种低紧急的查询任务,每隔10ms 查询一次按键状态,设置一个按键缓冲内存,三次按键都被按下说明没有抖动,这时才确定按键,这样做理论上不会有大冲突和延迟
 楼主| chen915 发表于 2020-9-13 22:27 | 显示全部楼层
雪山飞狐D 发表于 2020-9-12 14:38
设置一个全局最高优先级的定时器10ms , 做各种低紧急的查询任务,每隔10ms 查询一次按键状态,设置一 ...

嗯。谢谢。要是有代码就更好了现在的理解能力还离不开代码
 楼主| chen915 发表于 2020-9-13 22:27 | 显示全部楼层
andy520520 发表于 2020-9-12 10:50
印象中C51不支持3个以上的形参吧?

要怎样处理好一点?
雪山飞狐D 发表于 2020-9-14 05:35 | 显示全部楼层
chen915 发表于 2020-9-13 22:27
嗯。谢谢。要是有代码就更好了现在的理解能力还离不开代码

https://bbs.21ic.com/icview-2525970-1-1.html
我以前写的
 楼主| chen915 发表于 2020-9-14 08:43 | 显示全部楼层
雪山飞狐D 发表于 2020-9-14 05:35
https://bbs.21ic.com/icview-2525970-1-1.html
我以前写的

学习了,谢谢
ayb_ice 发表于 2020-9-14 09:11 | 显示全部楼层
andy520520 发表于 2020-9-12 10:50
印象中C51不支持3个以上的形参吧?

不是这样的,通过寄存器最多可以传递4个参数(取决于参数类型大小),其它参数通过固定内存传送,并没有什么限制
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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