完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
|
|
|
|
|
|
这种帖子真是太好了
|
|
|
|
|
|
太喜欢这种帖子了,
|
|
|
|
|
|
|
|
|
|
看了吴大师昨天的多任务评论。。。。今天终于看懂了一个以前的多任务程序的例子。。。。很高兴。。。。我是一只小乌龟。。。。每天不停的爬呀爬。。。。。
|
|
|
|
|
|
牛人 顶起
|
|
|
|
|
|
hello 还是我,Stone_up。 说明: 1、本章的目的是练习ADC,鸿哥的按键把AD按键排在最后,我想,在工程中用到的几率很小,但是我们有必要学习这一章。是练习AD的大好机会,所以必须抓住。 2、由于普通的单片机内部不带有AD,但是,STC12C5A60S2单片机内部自带AD,而且此单片机比普通单片机快12倍,很好用。所以,我以后更多的还是用此款单片机。 3、本章使用ADC通道0,即P1.0口,关于此款单片机的ADC使用,我也是刚刚边学便用的。所以不想过多的讲解,请大家自行学习。 4、我是来学习的,如有bug,欢迎大家指出,我会虚心接受。 疑问: 鸿哥,你程序中的这几个值是 根据理论值计算出来的还是通过实际采集的值?我知道理论值和实际采集的值有误差,所以我这几个值是通过实际采集得出的,然后扩大一下它们的范围。就这样。 #define cnt_key_nc 185 //没有按键按下时电压对应的AD数值 #define cnt_key1_up 185 //1号按键按下时电压对应的AD数值上限 #define cnt_key2_down 117 //2号按键按下时电压对应的AD数值下限 #define cnt_key2_up 137 //2号按键按下时电压对应的AD数值上限 #define cnt_key3_down 160 //3号按键按下时电压对应的AD数值下限 #define cnt_key3_up 175 //3号按键按下时电压对应的AD数值上限 /* * File Name : 主函数文件 * Description : 用中断方式 * Author : Stone * Time : 2013529 1:52:18 * Rev : V2 * Rev Description : * ---- * Histroy * Rev : V1 * Author : Stone */ /* * CPU : STC12C5A60S2 * 晶振: 11.0592MHz */ #include #include typedef unsigned char u8; typedef unsigned int u16; typedef unsigned char uint8; typedef unsigned int uint16; ***it BUZZER_OUT = P2 ^ 0; // 蜂鸣器输出IO ***it LED = P2 ^ 1; // LED输出IO /* 以下是STC12C5A60S2单片机寄存器定义 */ sfr ADC_CONTR = 0xBC; // ADC 控制寄存器 sfr ADC_RES = 0xBD; // ADC 转换结果寄存器 sfr ADC_RESL = 0xBE; // ADC 转换结果寄存器 sfr P1ASF = 0x9D; // P1口模拟功能控制寄存器 sfr AUXR1 = 0xA2; #define ADC_POWER 0x80 // ADC 电压控制位 #define ADC_FLAG 0x10 // ADC 转换结束标志位 由硬件置1 软件清零 #define ADC_START 0x08 // ADC 转换启动控制位 #define ADC_SPEEDLL 0x00 // 540个时钟周期转换一次 #define ADC_SPEEDL 0x20 // 360个时钟周期转换一次 #define ADC_SPEEDH 0x40 // 180个时钟周期转换一次 #define ADC_SPEEDHH 0x60 // 90个时钟周期转换一次 #define CNT_DELAY_CNT1 25 // 按键去抖动延时阀值 #define CNT_BUZZER_TIME 40 // 蜂鸣器声音长短阀值 #define CNT_KEY_NC 230 // 没有按键按下时电压对应的AD数值上限 #define CNT_KEY1_UP 20 // 1号按键按下时电压对应的AD数值上限 #define CNT_KEY2_DOWN 190 // 2号按键按下时电压对应的AD数值下限 #define CNT_KEY2_UP 210 // 2号按键按下时电压对应的AD数值上限 #define CNT_KEY3_DOWN 210 // 3号按键按下时电压对应的AD数值下限 #define CNT_KEY3_UP 230 // 3号按键按下时电压对应的AD数值上限 /* --------------------------------------- */ u8 key_step = 1; // 按键扫描步骤变量,在switch()括号里面 u8 key_lock1 = 0; // 按键自锁标志 u8 key_sec = 0; // 按键被触发的变量 u16 delay_cnt1 = 0; // 延时计数器的变量 u16 delay_cnt2 = 0; // 延时计数器的变量 u16 buzzer_time_cnt = 0; // 蜂鸣器声音长短的计数延时 u8 ad_step = 0; // AD扫描步骤变量 u8 key_value = 0; // 跟电压成比例关系的AD数值 u8 ad_flag = 0; // 用来指示单片机内部硬件AD处理完成标志 /* ------------------------------------------ */ void delay(u16 n); void adc_init(void); u8 get_adc_result(u8 ch); void key_scan(void); void key_service(void); void interrupt_init(void); int main(void) { adc_init(); interrupt_init(); BUZZER_OUT = 1; // 关闭蜂鸣器 while(1) { get_adc_result(0); key_service(); LED = 0; } return 0; } void timer0_interrupt(void) interrupt 1 { ET0 = 0; // 关闭定时器中断 IE &= ~0x20; // 关闭ADC中断 // EA = 0; key_scan(); // 按键扫描函数 if(buzzer_time_cnt) // 控制蜂鸣器声音的长短 { BUZZER_OUT = 0; // 开启蜂鸣器 --buzzer_time_cnt; // 蜂鸣器声音长短的计数延时 } else { BUZZER_OUT = 1; // 关闭蜂鸣器 } TH0 = 0xfe; TL0 = 0x33; ET0 = 1; // 前面关闭定时器中断,这里当然需要开启 IE |= 0x20; // 打开ADC中断 // EA = 1; } /* AD转换完成中断 */ void adc_routine(void) interrupt 5 { ET0 = 0; // 关闭定时器中断,避免两个中断相互扯淡 ad_flag = 1; // 置AD转换完成标志位 ET0 = 1; // 打开定时器中断 } void interrupt_init(void) { TMOD = TMOD | 0x01; TMOD = TMOD & 0xFD; TH0 = 0xfe; TL0 = 0x33; // 定时0.5ms TR0 = 1; IE |= 0x20; // 开启ADC中断允许位 ET0 = 1; // 开启外部中断 EA = 1; // 开启总中断 } void adc_init(void) { P1ASF = 0x01; // 开启ADC通道0 即P1.0口 ADC_RES = 0; // 清除以前的结果 AUXR1 &= ~0x04; //0000,0100, 令 ADRJ=0 ADC_CONTR = ADC_POWER | ADC_SPEEDLL; // 打开ADC电源,同时设置ADC转换速度 delay(2); // 加一个小延时 使输入电压达到稳定 return; } u8 get_adc_result(u8 ch) { switch(ad_step) { case 0: ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START; _nop_(); _nop_(); _nop_(); _nop_(); ad_step = 1; // 下一次循环进入下一个步骤 break; case 1: if(1==ad_flag) // ADC采样完成 { ad_flag = 0; key_value = ADC_RES; // 采集按键电压的AD值 ADC_CONTR &= ~ADC_FLAG; // 清零ADC转换结束标志位 ADC_CONTR &= ~ADC_START; // 关闭ADC转换 可以降低功耗 当然也可以不关闭 ad_step = 0; // 下一次循环切换回前面那个步骤 } break; default : break; } return (ADC_RES); // 返回ADC转换结果的高8位 } void key_scan(void) { if(key_value > CNT_KEY_NC) // 空闲 没有按键被按下 { key_lock1 = 0; // 按键自锁标志清零 delay_cnt1 = 0; // 按键去抖动延时计数器清零 } else if(key_lock1==0) // 有按键被按下,且是第一次被按下 { if(key_value < CNT_KEY1_UP) // KEY1 被按下 { ++delay_cnt1; // 延时计数器自加 if(delay_cnt1 > CNT_DELAY_CNT1) { delay_cnt1 = 0; key_lock1 = 1; // 按键自锁标志置位,避免一直触发 key_sec = 1; // 触发1号按键 } } else if(key_value > CNT_KEY2_DOWN && key_value < CNT_KEY2_UP) // KEY2 被按下 { ++delay_cnt1; if(delay_cnt1 > CNT_DELAY_CNT1) { delay_cnt1 = 0; key_lock1 = 1; // 按键自锁标志置位,避免一直触发 key_sec = 2; // 触发2号按键 } } else if(key_value > CNT_KEY3_DOWN && key_value < CNT_KEY3_UP) // KEY2 被按下 { ++delay_cnt1; if(delay_cnt1 > CNT_DELAY_CNT1) { delay_cnt1 = 0; key_lock1 = 1; // 按键自锁标志置位,避免一直触发 key_sec = 3; // 触发3号按键 } } } } void key_service(void) { switch(key_sec) { case 1: // 1 号按键 buzzer_time_cnt = CNT_BUZZER_TIME; key_sec = 0; // 处理完相应按键程序后,把按键选择变量清零,避免一直触发 break; case 2: // 2 号按键 buzzer_time_cnt = CNT_BUZZER_TIME; key_sec = 0; break; case 3: // 3 号按键 buzzer_time_cnt = CNT_BUZZER_TIME; key_sec = 0; break; } } void delay(u16 n) { u16 x; while (n--) { x = 5000; while (x--); } } 有图有真相,图在下一楼。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
求解外围电路实现的是4脚给持续低电平复位并正常工作,高电平不工作的原因
2084 浏览 1 评论
3629 浏览 3 评论
PIC1946程序有一个变量在运行过程中恢复初始值其他变量保持不变
2336 浏览 2 评论
2763 浏览 0 评论
PIC16F1825的RC5引脚,在主程序中操作无效,在中断中可以改变是为什么?
4027 浏览 5 评论
973浏览 0评论
用XC8编译PIC18F25K80时提示下面Error,求怎么解决这个问题
6360浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-4 05:49 , Processed in 1.207417 second(s), Total 102, Slave 87 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号