完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
电子发烧友论坛
|
呵呵。。我昨天也琢磨了,定时1ms运行正常,第二程序移植完毕,今天移植第三个程序。呵呵呵。。鸿哥加油。。等您写完了,出本书。绝对是玩单片机的好资料。 |
|
|
|
|
|
|
|
|
本帖最后由 qq328128752 于 2013-7-31 09:43 编辑
51移植程序大家给参考一下,delay1(unsigned int de)延时没有用到 //**********************************鸿哥程序移植********************************************** /*按键行列扫描与蜂鸣器 (1)技术体会:在行列式扫描结构的薄膜按键里,干扰很大,按键扫描程序非常讲究,尤其是去抖动的处理。 (2)功能需求:每按一个按键,蜂鸣器就响一次。 (3)硬件原理: (a)用4个IO来做2X2按键行列扫描,其中作为输入的2个IO口必须接上拉电阻20K左右。 (b)用1个IO经过8050三极管来驱动有源蜂鸣器,有源蜂鸣器通电就一直响,断电就停止。而无源蜂鸣器是要靠断断续续的开关信号来驱动才能响,就是要频率来驱动。 (4)源码适合的单片机:STC89C52RC,晶振为12MHz (5)源代码讲解如下: */ #include //补充说明:吴坚鸿程序风格是这样的,凡是输出IO后缀都是_dr,凡是输入的//IO后缀都//是_sr ***it beep_dr = P1^0; //蜂鸣器输出 ***it key_dr1 = P2^0;//2*2按键行输出 ***it key_dr2 = P2^1;//2*2按键行输出 ***it key_sr1 = P2^2;//2*2按键行输入 ***it key_sr2 = P2^3;//2*2按键行输入 //补充说明:吴坚鸿程序风格是这样的,凡是做延时计数阀值的常量前缀都用cnt_表示 #define cnt_delay_cnt1 25//按键去抖动延时阈值 #define cnt_delay_cnt2 5//按键行输出信号稳定的小延时阈值 #define cnt_voice_time 60//蜂鸣器响的声音长短的延时阈值 void delay1(unsigned int de);//小延时程序,时间不宜太长,因为内部没有看门狗 //补充说明:吴坚鸿程序风格是这样的,凡是按键扫描函数都放在定时中 //断里,凡是按键服务程序都是放在main函数循环里。有人说不应该把子程序//放在中断里,别听他们,信鸿哥无坎坷。 void key_can();//按键扫描函数,放在定时中断里 void key_service(); //按键服务函数,放在main 函数循环里 //补充说明:吴坚鸿程序风格是这样的,凡是switch()语句括号里面的变量名 //后缀都用_step表示。 unsigned char key_step=1;//按键扫描步骤变量,在switch()语句的括号里 //补充说明:吴坚鸿程序风格是这样的,凡是按键或者感应输入的自锁变量名 //后缀都用_lock表示。 unsigned char key_lock1=0;//按键自锁标志 //补充说明:吴坚鸿程序风格是这样的,凡是计数器延时的变量 //后缀都用_cnt表示。 unsigned int delay_cnt1=0; //延时计数器的变量 unsigned int delay_cnt2=0; //延时计数器的变量 unsigned int voice_time_cnt; //蜂鸣器响的声音长短的计数延时 //补充说明:吴坚鸿程序风格是这样的,凡是做类型的变量的分类 //后缀都用_sec表示。 unsigned char key_sec=0; //哪个按键被触发 main() { TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响 TH0=0x1c; //给定初值,这里1ms TL0=0x18; EA=1; //总中断打开 ET0=1; //定时器中断打开 TR0=1; //定时器开关打开 beep_dr=0; //关蜂鸣器,上电初始化IO while(1) { // CLRWDT(); //喂看门狗,大家不用过度关注此行 key_service(); //按键服务 } } void key_scan() //按键扫描函数 { //补充说明:如果中断一次就把所有的按键都扫描完,中断占用的时间片就会太多,势//必会影响main函数里其他子程序的运行,为了避免一口气把所//的按键都扫描完,此 //处用switch语句把4个按键分成2等分,一次中断只扫描2个按键 switch(key_step) //按键扫描步骤, { case 1: //扫描1号键,2号键 key_dr1=0; //按键行扫描输出第一行低电平 key_dr2=1; delay_cnt2=0; //延时计数器清零 key_step++; //切换到下一个运行步骤 break; case 2: delay_cnt2++; if(delay_cnt2>cnt_delay_cnt2) //小延时,但不是去抖动延时,替代一直受网友争议的delay1(40) { delay_cnt2=0; key_step++; //切换到下一个运行步骤 } break; case 3: if(key_sr1==1&&key_sr2==1) { //如果没有按键按下,则2个IO输入都是高电平 key_step++; //如果没有按键按下,下一个中断扫描下2个按键 key_lock1=0; //按键自锁标志清零 delay_cnt1=0; //按键去抖动延时计数器清零,此行非常巧妙 } else if(key_sr1==0&&key_sr2==1&&key_lock1==0) { // key_lock1按键自锁,避免按键一直触发,下降沿有效 ++delay_cnt1; //延时计数器 //补充说明:有按键触发之后,不要马上响应,要延时一段时间去抖动,此处本人设计非常 //巧妙,很多人仅仅知道按键延时的时候要保证还能去处理别的程序,这样是还不够的, //在延时去抖动的时候,还必须要监控延时这段时间里,按键IO输入口是否会由于受到某//种干扰突然由低变成高,如果一旦变成高,那么延时计数器delay_cnt1必须重新清零 //我当年就是因为这样处理,把卖给富士康100台受干扰死机的设备修好了,老板马上 //给我加薪1000元。 if(delay_cnt1>cnt_delay_cnt1) //延时计数器超过一定的数值 { delay_cnt1=0; key_lock1=1; //自锁按键置位,避免一直触发,只有松开按键,此标志位才会被清零 key_sec=1; //触发1号键 } } else if(key_sr1==1&&key_sr2==0&&key_lock1==0) { ++delay_cnt1; if(delay_cnt1>cnt_delay_cnt1) { delay_cnt1=0; key_lock1=1; //自锁按键置位,避免一直触发 key_sec=2; //触发2号键 } } break; case 4: //扫描//扫描3号键,4号键 key_dr1=1; key_dr2=0; //按键行扫描输出第二行低电平 delay_cnt2=0; //延时计数器清零 key_step++; //切换到下一个运行步骤 break; case 5: delay_cnt2++; if(delay_cnt2>cnt_delay_cnt2) //小延时,但不是去抖动延时,替代一直受网友争议的delay1(40) { delay_cnt2=0; key_step++; //切换到下一个运行步骤 } break; case 6: if(key_sr1==1&&key_sr2==1) { key_step++; key_lock1=0; delay_cnt1=0; } else if(key_sr1==0&&key_sr2==1&&key_lock1==0) { ++delay_cnt1; if(delay_cnt1>cnt_delay_cnt1) { delay_cnt1=0; key_lock1=1; key_sec=3; //触发3号键 } } else if(key_sr1==1&&key_sr2==0&&key_lock1==0) { ++delay_cnt1; if(delay_cnt1>cnt_delay_cnt1) { delay_cnt1=0; key_lock1=1; //自锁按键置位,避免一直触发 key_sec=4; //触发4号键 } } break; } if(key_step>6) //第1组按键与第2组按键反复轮流扫描 { key_step=1; } } void key_service() //按键服务函数 { switch(key_sec) //按键服务状态切换 { case 1:// 1号键 // 补充说明:voice_time_cnt只要不为0蜂鸣器就会响,中断里判断voice_time_cnt不为0时,会不断自减,一直到它为0时,自动把蜂鸣器关闭 voice_time_cnt= cnt_voice_time; //蜂鸣器响“滴”一声就停 key_sec=0; //相应完按键处理程序之后,把按键选择变量清零,避免一直触发 break; case 2:// 2号键 voice_time_cnt= cnt_voice_time; //蜂鸣器响“滴”一声就停 key_sec=0; //相应完按键处理程序之后,把按键选择变量清零,避免一直触发 break; case 3://3号键 voice_time_cnt= cnt_voice_time; //蜂鸣器响“滴”一声就停 key_sec=0; //相应完按键处理程序之后,把按键选择变量清零,避免一直触发 break; case 4://4号键 voice_time_cnt= cnt_voice_time; //蜂鸣器响“滴”一声就停 key_sec=0; //相应完按键处理程序之后,把按键选择变量清零,避免一直触发 break; } } void Timer0_isr(void) interrupt 1 using 1 { TR0=0; //定时中断开关关闭 key_scan(); //按键扫描函数 if(voice_time_cnt) //控制蜂鸣器声音的长短 { beep_dr=1; //蜂鸣器响 --voice_time_cnt; //蜂鸣器响的声音长短的计数延时 } else { beep_dr=0; //蜂鸣器停止 } TH0=0x1c; //重新设置定时时间间隔 TL0=0x18; TR0=1; //定时中断开关打开 } void delay1(unsigned int de) { unsigned int t; for(t=0;t |
|
|
|
|
|
|
|
|
第二个程序移植
//鸿哥程序移植 /*第二节:独立按键扫描与蜂鸣器 (1)学习目标:利用上一节的程序框架,把按键行列扫描方式改成独立按键扫描方式。通过这节的练习,加深熟悉吴坚鸿的程序框架,以及独立按键扫描的编程方式。 (2)功能需求:每按一个按键,蜂鸣器就响一次。 (3)硬件原理: (a)用4个IO来做独立按键扫描, 4个IO口都必须接上拉电阻20K左右。 (b)用1个IO经过8050三极管来驱动有源蜂鸣器,有源蜂鸣器通电就一直响,断电就停止。 (4)源码适合的单片机:PIC18F4620,晶振为22.1184MHz (5)源代码讲解如下: */ #include //补充说明:吴坚鸿程序风格是这样的,凡是输出IO后缀都是_dr,凡是输入的//IO后缀都//是_sr ***it beep_dr=P1^1; //蜂鸣器输出 ***it key_sr1= P1^2; //独立按键输入 ***it key_sr2= P1^3; //独立按键输入 ***it key_sr3= P1^4; //独立按键输入 ***it key_sr4= P1^5;//独立按键输入 //补充说明:吴坚鸿程序风格是这样的,凡是做延时计数阀值的常量 //前缀都用cnt_表示。凡是延时常量,都应该根据上机实际情况来调整出最佳的数值 #define cnt_delay_cnt1 25 //按键去抖动延时阀值 #define cnt_voice_time 60 //蜂鸣器响的声音长短的延时阀值 //补充说明:吴坚鸿程序风格是这样的,凡是按键扫描函数都放在定时中 //断里,凡是按键服务程序都是放在main函数循环里。有人说不应该把子程序//放在中断里,别听他们,信鸿哥无坎坷。 void key_scan(); //按键扫描函数,放在定时中断里 void key_service(); //按键服务函数,放在main函数循环里 //补充说明:吴坚鸿程序风格是这样的,凡是switch()语句括号里面的变量名 //后缀都用_step表示。 unsigned char key_step=1; //按键扫描步骤变量,在switch()语句的括号里 //补充说明:吴坚鸿程序风格是这样的,凡是按键或者感应输入的自锁变量名 //后缀都用_lock表示。 unsigned char key_lock1=0; //按键自锁标志 unsigned char key_lock2=0; //按键自锁标志 unsigned char key_lock3=0; //按键自锁标志 unsigned char key_lock4=0; //按键自锁标志 //补充说明:吴坚鸿程序风格是这样的,凡是计数器延时的变量 //后缀都用_cnt表示。 unsigned int delay_cnt1=0; //延时计数器的变量 unsigned int delay_cnt2=0; //延时计数器的变量 unsigned int delay_cnt3=0; //延时计数器的变量 unsigned int delay_cnt4=0; //延时计数器的变量 unsigned int voice_time_cnt; //蜂鸣器响的声音长短的计数延时 //补充说明:吴坚鸿程序风格是这样的,凡是做类型的变量的分类 //后缀都用_sec表示。 unsigned char key_sec=0; //哪个按键被触发 main() { TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响 TH0=0x1c; //给定初值,这里1ms TL0=0x18; EA=1; //总中断打开 ET0=1; //定时器中断打开 TR0=1; //定时器开关打开 beep_dr=0; //关蜂鸣器,上电初始化IO while(1) { // CLRWDT(); //喂看门狗,大家不用过度关注此行 key_service(); //按键服务 } } void key_scan() //按键扫描函数 { //补充说明:因为独立按键扫描没有了行列按键扫描的delay1(40)延时,所以速度很 //快,可以一次中断扫描完所有的按键,不用switch(key_step)语句来分段 if(key_sr1==1) //IO是高电平,说明按键没有被按下,这时要及时清零一些标志位 { key_lock1=0; //按键自锁标志清零 delay_cnt1=0; //按键去抖动延时计数器清零,此行非常巧妙 } else if(key_lock1==0) //有按键按下,且是第一次被按下 { ++delay_cnt1; //延时计数器 if(delay_cnt1>cnt_delay_cnt1) { delay_cnt1=0; key_lock1=1; //自锁按键置位,避免一直触发 key_sec=1; //触发1号键 } } if(key_sr2==1) //IO是高电平,说明按键没有被按下,这时要及时清零一些标志位 { key_lock2=0; //按键自锁标志清零 delay_cnt2=0; //按键去抖动延时计数器清零,此行非常巧妙 } else if(key_lock2==0) //有按键按下,且是第一次被按下 { ++delay_cnt2; //延时计数器 if(delay_cnt2>cnt_delay_cnt1) { delay_cnt2=0; key_lock2=1; //自锁按键置位,避免一直触发 key_sec=2; //触发2号键 } } if(key_sr3==1) //IO是高电平,说明按键没有被按下,这时要及时清零一些标志位 { key_lock3=0; //按键自锁标志清零 delay_cnt3=0; //按键去抖动延时计数器清零,此行非常巧妙 } else if(key_lock3==0) //有按键按下,且是第一次被按下 { ++delay_cnt3; //延时计数器 if(delay_cnt3>cnt_delay_cnt1) { delay_cnt3=0; key_lock3=1; //自锁按键置位,避免一直触发 key_sec=3; //触发3号键 } } if(key_sr4==1) //IO是高电平,说明按键没有被按下,这时要及时清零一些标志位 { key_lock4=0; //按键自锁标志清零 delay_cnt4=0; //按键去抖动延时计数器清零,此行非常巧妙 } else if(key_lock4==0) //有按键按下,且是第一次被按下 { ++delay_cnt4; //延时计数器 if(delay_cnt4>cnt_delay_cnt1) { delay_cnt4=0; key_lock4=1; //自锁按键置位,避免一直触发 key_sec=4; //触发4号键 } } } void key_service() //按键服务函数 { switch(key_sec) //按键服务状态切换 { case 1:// 1号键 // 补充说明:voice_time_cnt只要不为0蜂鸣器就会响,中断里判断voice_time_cnt不为0时,会不断自减,一直到它为0时,自动把蜂鸣器关闭 voice_time_cnt= cnt_voice_time; //蜂鸣器响“滴”一声就停 key_sec=0; //相应完按键处理程序之后,把按键选择变量清零,避免一直触发 break; case 2:// 2号键 voice_time_cnt= cnt_voice_time; //蜂鸣器响“滴”一声就停 key_sec=0; //相应完按键处理程序之后,把按键选择变量清零,避免一直触发 break; case 3://3号键 voice_time_cnt= cnt_voice_time; //蜂鸣器响“滴”一声就停 key_sec=0; //相应完按键处理程序之后,把按键选择变量清零,避免一直触发 break; case 4://4号键 voice_time_cnt= cnt_voice_time; //蜂鸣器响“滴”一声就停 key_sec=0; //相应完按键处理程序之后,把按键选择变量清零,避免一直触发 break; } } void Timer0_isr(void) interrupt 1 using 1 { TR0=0; //定时中断开关关闭 key_scan(); //按键扫描函数 if(voice_time_cnt==60) //控制蜂鸣器声音的长短 { beep_dr=1; //蜂鸣器响 --voice_time_cnt; //蜂鸣器响的声音长短的计数延时 } else { beep_dr=0; //蜂鸣器停止 } TH0=0x1c; //重新设置定时时间间隔 TL0=0x18; TR0=1; //定时中断开关打开 } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
不要说我回复的多 先在这里解释下 今天才看到此贴 从第一页看的 嘻嘻 程序飘过等等看 我现在基本上至少泡半天 |
|
|
|
|
|
|
|
|
我也是90后的 你现在是什么程度呀 一起探讨下 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RTX51操作系统可以实现多任务并行处理,很方便,虽然局限在51上,不过省去了定时之类的麻烦
|
|
|
|
|
|
|
|
|
楼主的无私让在下感动的无以复加
|
|
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
求解外围电路实现的是4脚给持续低电平复位并正常工作,高电平不工作的原因
2382 浏览 1 评论
4242 浏览 3 评论
PIC1946程序有一个变量在运行过程中恢复初始值其他变量保持不变
2619 浏览 2 评论
3118 浏览 0 评论
PIC16F1825的RC5引脚,在主程序中操作无效,在中断中可以改变是为什么?
4577 浏览 5 评论
有套STM32与西门子200程序需要代写,有兴趣的工程师与有联系!
2491浏览 1评论
用XC8编译PIC18F25K80时提示下面Error,求怎么解决这个问题
6801浏览 0评论
/9
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-12-18 00:35 , Processed in 1.308164 second(s), Total 85, Slave 76 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191

淘帖