按开机键和键盘上的加减乘除在哪键刷屏没用

手机开机后进不了系统,按开机键和音量减出现
全部答案(共3个回答)
模式开测试一些重力感应之类的 现在关机按住电源键和音量加减进入工厂模式 用音量加减移动光条wipe data/factory reset 找到这个按电源键
手机双清,操作方:同时按住电源键和音量上键进入
以下两项:
wipe data/factory reset
wipe cache
用音量上和下进行选择,电源键确...
把手机恢复出厂设置就可以了 不行的话可以考虑刷机
把内存卡 取出 在恢复出厂设置
首先确定你要进的是recovery模式还是Fastboot模式
recovery是在关机状态按电源键+音量加 3-5秒后放开
Fastboot是在关机状态按电源...
根据您的描述,
那是因为 Root大师 是有型号的针对性.
不适配的型号或少众品牌用它来Root,
便容易发生系统错乱, 有进不了系统的情况了 !!
不过, 您...
开机键加音量键+是开机哦 开机键加音量键-是进入工厂模式
答: 如果手机自带的有 刷机包,就按下面的方法试试吧,按电源键加音量上键《有的是音量下键》加房子键,会出现挖煤模式,点击擦除手机全部数据,再重启手机就行了。Pin码一...
答: 美国苹果公司的新款手机,全触屏的智能机,在中国卖的很贵。
答: 主流手机配置,不错的一个选择。
答: 美国苹果公司的新款手机,全触屏的智能机,在中国卖的很贵。
大家还关注
Copyright &
Corporation, All Rights Reserved
确定举报此问题
举报原因(必选):
广告或垃圾信息
激进时政或意识形态话题
不雅词句或人身攻击
侵犯他人隐私
其它违法和不良信息
报告,这不是个问题
报告原因(必选):
这不是个问题
这个问题分类似乎错了
这个不是我熟悉的地区
相关问答:123456789101112131415金立手机进入了刷屏模式然后长按了开机键和音量键十五秒就成这样了怎么办_百度知道
金立手机进入了刷屏模式然后长按了开机键和音量键十五秒就成这样了怎么办
我有更好的答案
apply开头的那两行第一个是从sd卡选择刷机包,第二个是从手机内存选择刷机包
采纳率:60%
选第六项英文就行了
怎么选按她没反应
按音量减健选到第六项然后按开机健按一下然后出英文选择yes等5,6分钟,把电池拔了,开机ok
减键按不动
为您推荐:
其他类似问题
金立手机的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。华为的音量加减和开机键同时按,就这样了,怎么办?_百度知道
华为的音量加减和开机键同时按,就这样了,怎么办?
我有更好的答案
应该是刷机了
那又怎么办?
是不是一直像这样
这个圈有没有在转
一直在转,要怎么搞?这干什么?
就是在刷机
我手机刷机也会有这样的图片
刷机又是干啥?
。。。。。。。。
我是想重装系统,不是刷机。
那你得去手机店去重装系统
你是不是想把系统改成其他的
我现在可以退出吗?怎么退出?退出了我就采纳
我是想升级系统,但手机root了,所以只能用卡来重装系统
你一直按着开机键试试看
重新启动了,很好!!!快恭喜。
可以了是吗
本人对电脑很了解,对手机一窍不通。
我只知道手机卡了可以这样,没想到刷机也可以这样😂😂😂😂😂😂😂😂
本人对手机了解,对电脑一窍不通
滴水之恩当涌泉相报,你电脑有什么问题尽管找我,比如说你电脑待会死机,或者蓝屏或者木马攻击或者黑客袭击,尽管找我
我电脑已经报废了
得再买显示屏
呃。。。。。
和音响那些
一前的电脑是笔记本,现在的电脑是台式
还不如买一套新的,拼接起来可能会有些不兼容,显示器蛮贵的
好像是显示屏
嗯,祝你好运!
采纳率:16%
这是开发测试人员使用的,建议楼主长按关机键关机!
我要刷机呢?
电脑下载个刷机精灵手机开启Usb调试,按照提示刷机
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。> 刷屏文章
热门文章热门标签
08月01日 |
08月01日 |
08月01日 |
08月01日 |
08月01日 |
08月01日 |
08月01日 |
08月01日 |赞助商链接
当前位置: >>
快速培训(带备注和录像)new
LaunchPad 口袋实验平台 ―MSP-EXP430G2篇1 第1讲 CCS软件应用基础青岛大学-美国德州仪器MSP430单片机共建实验室傅强2 1.1 安装CCS? 不要使用中文路径? 许可文件向TI中国大学计划部索取,供100台计算机同时使用。3 1.2 CCS的Workspace工作空间(文件夹)Workspace工程(文件夹)ProjectProject文件/文件夹main.cFileDocumentmain.cFileFile4 WorkSpace有什么用?? 只有同一个WorkSpace文件夹的工程,可以显示在同一软件界面中,随 时激活编辑和使用。5 更改CCS的Workspace方法1? 在安装到“Select a workspace”的时候,可以不勾选图2.2中的小框。 那样的话,每次启动CCS都会询问,更改Workspace将会很方便。6 更改CCS的Workspace的方法2? 除了在启动CCS时选择WorkSpace外,还可以电点击File?Switch Workspace。CCS将会重新启动,切换到新的Workspace。7 1.3 新建或添加工程和文件? 只能在同一个Workspace中新建或添加工程。8 添加现有工程? 点击File?Import?Existing CCS/CCE Eclipse Projects9 ? 按一般的浏览文件夹方法选择已存在的工程即可? 注意,勾选上Copy projects into workspace,这样一旦选择的即使不是 当前workspace文件夹中的工程,也会“强行”复制到当前workspace中 。10 1.4 外部文件? 在任何一个工程中,都包含main.c文件,还可以有很多其他文件。? 在Project Explorer树形目录中,可以通过新建或者直接COPY的方法增 加文件夹或c文件、h文件。11 1.5 外部文件的路径问题? 仅仅将外部文件和文件夹“加”进工程,而不做其他处理,编译时会出 现找不到source file的错误。12 ? 在工程目录下,专门有一个Include,表示外部文件的路径。? 如图所示的两个路径是系统自带的,并没有解决src文件夹的路径问题13 ? 在工程名上点击右键菜单,选择最后一项“Properties”,点击 “Include Options”? 点击添加外部文件路径。14 ? 外部文件应该放在workspace文件夹的相应工程文件夹中,便于管理。? 最好使用相对路径,而不是绝对路径,好处不言而喻。 ? 箭头指示部分的意思是外部文件放在了“工作空间中的工程文件夹下的 src文件夹里。”15 ? 例子中这个工程的外部文件放在了工程名文件夹下面的src文件夹里? 左图是缺少外部文件路径的Includes ? 右图则包含有正确的路径配置16 1.6 程序的编译、下载、仿真、调试? 程序编写完成后,点击 提示窗逐条修改错误。 即可开始编译。根据图中所示的编译错误17 ? 点击行下载和仿真了,耐心等待后,得到仿真调试界面。开始运行程序? 完成后,代码被下载到G2单片机里,点击18 1.7 CCS创建工程举例? 闪烁灯程序:P1.6接LED,通过长延时实现LED闪烁。19 不引用外部文件的函数#include &MSP430G2553.h& void main() { WDTCTL = WDTPW + WDTHOLD; //关狗 P1DIR =BIT6; //P1.6设为输出 while(1) { Blink_LED(); //调用子函数 } } /****************************************************************************************************** * 名 称:Blink_LED() * 功 能:控制LED亮灭 * 说 明:通过长延时控制LED亮灭 ******************************************************************************************************/ void Blink_LED() { _delay_cycles(1000000); P1OUT^=BIT6; //LED亮灭改变 }20 练习1.1:引用外部文件中的函数? 建立Sample工程? 在工程中添加src文件,添加“Sample/src”路径 ? 新建Blink.c ,将Blink_LED()函数写进去 ? 新建Bilnk.h文件,将extern void Blink_LED()写入,表示其为外部函数? 在main.c中包含头文件,#include “Blink.h”21 1.8 CCS观测数据举例? CCS的Graph功能可以将数组数据以“波形图”的方式显示出来。? 下面的程序中,将构造一个三角波数据数组#include &msp430.h& unsigned char DataTable[128]={0}; void main(void) { int i = 0; WDTCTL = WDTPW + WDTHOLD; //关闭看门狗定时器 while(1){ for(i=0;i&128;i++){ if(i&64) DataTable[i] =i; else DataTable[i] =128-i; } _NOP(); //此处设置断点 } }22 ? 在仿真运行后,点击Tool?Graph?Single Time ? Acquisition Buffer Size ? Dsp Data Type? Start Address? Display Data Size23 ? 在断点位置点击右键,编辑断点属性。将Action改为Refresh All Windows,这样就可以连续更新波形。24 ? Display Data Size设为的显示效果25 练习1.2:自行构造一个波形数组,并显示出来声明一个数组 (256字节以 下)用某种方式给 数组赋值(一 个一个写也行)仿真运行观测波形配置graph26 1.9 Grace功能? Grace(Graphical Code Engine)图形化代码引擎,可以用点鼠标的方 法配置功能寄存器。? 一个普通工程不能“半路出家”转变成Grace工程,一定要在新建工程 的时刻就选为Grace工程。27 Grace的图形化操作? 在工程浏览窗口点击main.cfg[Grace],接着在主窗口点击Device Overview进入可配置资源框图。28 DVCC BCS+ Flash ADC10Port Comp_A+WDT+ Timer_A USCI_A&B29 Grace 配置BCS举例? 先勾选Enable xxx(时钟模块默认被勾选),然后就会出现Overview、 Basic User、Power User、Register四个按钮。30 31 相当于提供了说明书? 每个寄存器都按高低字节顺序 排列? 组合功能位则有下拉菜单 ? 鼠标放在每个选项上都会有相 应的说明 ? 不属于本模块的控制位,是不 可选的32 1.10 Grace代码的移植? 我们点击文件保存 ,就完成 了对时钟模块的配置。? 点击 激活当前工程. ? 再点击 进行编译。? 耐心等待完成,杀毒软件可能会 警报,请配合放行。? 工程目录中多出src文件夹33 34 练习1.3 利用Grace配置系统时钟代码新建一个Grace 工程利用Grace的菜 鸟模式配置各种 CPU时钟将Grace配置的 BCSplus_init() 函数找出来移植观测闪烁灯的闪 烁频率变化改变闪烁灯工程 的CPU时钟35 第2讲 扩展板硬件原理青岛大学-美国德州仪器MSP430单片机共建实验室傅强36 2.1 供电单元? 非“轨至轨”单电源供电的运放,不仅无法处理负电压信号, 甚至接近0V的正电压信号也是不能处理的。C 由于扩展板需要对双极性信号进行处理,所以使用了双电源供电的 运放。37 电荷泵反压电路原理? Q1和Q3闭合,飞电容C(flying capacitor)被正电源充上左正右负的电 压。? Q1和Q3断开后,Q2和Q4闭合,飞电容C给滤波电容CF充上下正上负的 电容。38 2.2 触摸板单元? 电容触摸的实现方案大体分测RC振荡频率和测RC充电时间C G2系列单片机的IO内部有施密特反相器原理的振荡电路,所以无需外部器件 即可实现电容触摸。39 2.3 I2C扩展IO单元? 对于低速的IO,可以通过串行转并行的方法扩展。? I2C接口控制的IO扩展芯片TCA6416A,扩展出16个双向IO。40 TCA6416A41 机械按键及LED灯柱? 4个机械按键? 8个LED42 2.4 LCD显示单元? HT1621 ? 128段LCD驱动器43 44 2.5 PWM与滤波器单元45 2.6 双极性信号采样单元? 3个电阻构成电平偏置网络,解决用单极性ADC对双极性信号采样的难题46 2.7 Slope ADC单元? 仅用1个比较器可以构成的Slope型ADC(积分型)。? 它可以用来测量大量基于电阻值改变原理构成的传感器47 2.8 TF卡单元? TF卡也叫MircoSD卡,与SD卡的引脚操作几乎完全一致。C 一个TF卡座加上1个上拉电阻,两个滤波电容便可用上物美价廉的TF卡。 C 不仅获得物美价廉的存储空间,而且可以学习SPI通信原理。48 2.9 DAC单元? DAC11 做一个基于DDS的任意波形发生器AWG。C DDS:Direct Digital Synthesizer直接数字式频率合成 C AWG:Arbitrary Waveform Generator任意波发生器49 2.10 音频功放单元? 除了可以用眼睛看示波器的模拟信号,其实还可以用耳朵听模拟信号。C 用DAC加上音频功放TPA301播放音频的方案可以实现音频播放 C 同时TF卡可以提供海量的音频数据。50 使用蜂鸣器播放音乐? 使用无源蜂鸣器充当喇叭,效果不可思议的居然还行!C 由于音频播放属于重负载电路,电流很大,所以做其他实验时,应拔掉蜂鸣 器,避免影响整板供电。51 练习2.1:烧录全部实验例程,观测现象? 打开预存在计算机上的“实验例程录像”文件夹? 打开实验例程录像ppt,即可获得全程指导。C 通过ppt播放视频,不要直接打开视频52 第3讲 MSP430的时钟与定时器青岛大学-美国德州仪器MSP430单片机共建实验室傅强53 3.1 为什么要搞这么多系统时钟?? 单片机的低功耗主要是依靠间歇工作实现的,而间歇工作的方 法就是启停系统时钟。? 如果像普通51单片机那样只有一个时钟,关掉时钟意味着单片 机全面停工,节能的同时也没法正常使用了。54 3.2 MSP430单片机的系统时钟MCLK主时钟(Main system Clock)? MCLK频率配置的越高,CPU执行的速度越快。 ? CPU速度越快功耗也越高,但高频率的MCLK可以让CPU工作时 间更短。SMCLK:子系统时钟(Sub-main Clock)? 需要高速时钟的片内外设提供服务,比如定时器和ADC采样等。 ? 当CPU休眠时,只要SMCLK开启,定时器和ADC仍可工作。ACLK:辅助时钟(Auxillary Clock)? 辅助时钟的频率很低,所以即使一直开启功耗也不大 ? 辅助时钟可以供给那些只需低频时钟的片内外设 ? 与定时器配合间歇唤醒CPU。55 3.3 系统时钟的来源? 处于成本和使用方便的考虑,时钟的来源也是多种多样的。系统时钟高频时钟 MCLK SMCLK低频时钟 ACLK片内片外片内片外数控振荡器 DCO锁频环 PLL高频晶振低频振荡器 VLO低频晶振 (32.768kHz)56 锁频环FLL原理? 分频容易,倍频难;计数器就是分频器。? FLL基于负反馈原理,频率精确稳定。数控振荡器 DCO时钟输出2MHz加减计数器+32.768kHz 晶振数控分频器 分频系数6157 DCO原理RC振荡器? RSELx ? 选择振荡电阻分频器? DCOx ? 选择分频系数混频器? MODx ? 选择混频系数58 混频原理? 用不同比例交替输出两种频率信号,就是混频C 混频信号的总周期包含32个脉冲 C MODx用来决定两种信号所占的个数。59 3.4 时钟的配置? VLO和DCO都是开环振荡 器。ACLK选晶 振还是VLO? 输出频率会随温度和供电 电压变化。 ? 所以,有32.768kHz晶振 就别选VLOMCLK和 SMCLK选 DCO DCO的三个参数 RSELx DCOx MODx? DCO的三个参数用现成的 ,不要自己去配置。 ? 什么代码不用写,默认就 配置成32.768kHz? DCO参数配成1MHz60 DCO的出厂校验参数每块G2单片机的都存有出厂4种DCO的RSELx、DCOx、MODx的参数。61 62 3.5 低功耗模式停止振荡 关闭输出省电 唤醒慢费电 唤醒快停止低功耗 模式关闭63 节能模式的功耗对比64 LPM0与LPM3? 实际只有LPM0和LPM3最有用。? LPM4可以用来当关机。65 吱一声就能进出低功耗模式66 3.6 定时器概述? 定时器其实就是计数器,如果是对恒频脉冲计数,就成了定时器。? 根据定时达到后,引发的事件不同,可分为BT、WDT、TA几种类型。Basic Timer 简称BT Watch Dog Timer简称WDT Timer_A 比较模块 Timer_A 捕获模块闹钟 OUTPUT 定时值比较 有限闹钟 OUTPUT 就几个定时 值 引发中断 引发复位闹钟 OUTPUT挂钟 INPUT定时值任意首选24小时引发中断引发中断 控制IO输出瞬间记录事 件发生时间67 3.7 定时节拍? BT和WDT经常做为节拍“闹钟”来使用,实现CPU的无阻塞与低功耗。 ? 下面的例子中,闹钟被设定为5分钟响一次。每5分钟去查看敲 门 ? 没有门铃(外部 中断),需要守 在门口接客吗? ? 如果客人敲门至 少持续5分钟。 ? 每次闹钟响去看 一次门即可,其 他时间休眠。5分钟能烧开一壶 水 ? 人(CPU)只需 开火和关火两个 操作,其他时间 都可以休眠 ? 先开火?休眠? 响铃?关火?收 工每1小时吃一次药 ? 一个闹钟也可以 完成多种任务。 ? 休眠?响铃?记 下响铃次数?休 眠?响铃12次? 吃药?响铃次数 清零?重复68 3.8 TimerA的结构? 为了解放CPU的生产力,定时器被赋予了辅助功能。69 3.9 TA的主定时器? 处于方便的考虑,我们可能需要正常计时,也可能会用倒计时。? 可能会按24小时循环,也可能是12小时循环,当然还可能是别的时间。MCx=10,连续计数;相当于24小时制。70 ? MCx=01,增计数模式? 相当于设定任意小时制,由TACCR0寄存器决定。 ? TACCR0的地位比TACCR1和TACCR0要特殊。71 ? MCx=11,增减计数? 也相当于设定任意小时制,同样由TACCR0决定时长。 ? 只不过“到点”后不是归零,而是变倒计时。72 TA主定时器的中断? 为什么搞这么复杂的多功能时钟呢?一切都是为了PWM!? 主定时器的中断时刻因计数模式不同而不同。73 3.10 捕获/比较模块CCRx? Timer_A的有捕获/比较模块CCRx并不是独立的功能模块,它们都必须 依靠16位主定时器工才能工作。捕获模块Capture? 可以判断输入信号的 边沿,并瞬间用 TACCRx寄存器记录 下边沿时刻(TAR值) ? 用于精确测定脉宽或 频率比较模块 Comparator? 通过将TAR寄存器值 与TACCRx中预设值 比较,自动按“预设方 案”反转IO电平 ? 可以自动生成各种 PWM波形CAP寄存器? 捕获/比较共用了 TACCRx寄存器,所 以不能同时使用。 ? CAP寄存器位用于选 择捕获/比较工作模式。 ? CAP=0为比较, CAP=1为捕获。74 3.11 捕获模块? 主定时器一般设置为连续计数模式,以提供最大时间刻度。? 当CCRx检测到CCIx(某带捕获功能的IO口)的电平边沿时,瞬间读取 TAR寄存器的值并写入TACCRx。 ? 下降沿-上升沿=脉宽 上升沿-上升沿=周期75 硬件捕获法与中断法的对比 外部中断法? 边沿被检测?触发中 断?进中断子函数? 立刻读取定时器值 ? 这时读取的定时器值 和实际边沿的时刻有 较大的误差。捕获法? 边沿被检测?立刻读 取定时器值TAR锁存 到CCRx模块内 TACCRx寄存器?触 发中断?爱什么时候 读什么时候去读 TACCRx。 ? 这样的误差延迟就仅 有十纳秒级。76 配置捕获功能? SCS寄存器控制同步捕获还是异步捕获,一般均设为同步捕获。 ? 标志位COV=1代表数据覆盖,上次TACCRx的数据没被取走,而又新来 数据覆盖了TACCRx的异常情况。使用捕获功能时的流程MCx=10 主定时器连续计数CAP=1 拨到捕获档配置CCISx 选择捕获IO配置CMx 选择捕获沿读取 TACCRx77 3.12 比较模块与PWM? 当CCR1/2发现TAR的值与TACCR0或它们自己的TACCRx相等时,便会 自动改变输出IO口TAx的输出电平,从而生成波形。? 改变的规则由OUTMODx寄存器决定,共有8种规则。78 OUTMODEx规则OUTMODx 000(模式0) 001(模式1) 010(模式2) 输出模式 电平输出 延迟置位 取反/清零 描述 TAx管脚由OUTx位决定高低电平 当主计数器计到TACCRx时,TAx管脚置1当主计数器计到TACCRx时,TAx管脚取反 当主计数器计到TACCR0时,TAx管脚置0当主计数器计到TACCRx时,TAx管脚取1 当主计数器计到TACCR0时,TAx管脚置0 当主计数器计到TACCRx时,TAx管脚取反 当主计数器计到TACCRx时,TAx管脚取0 当主计数器计到TACCRx时,TAx管脚取反 当主计数器计到TACCR0时,TAx管脚置1011(模式3) 100(模式4) 101(模式5) 110(模式6)置位/清零 取反 延迟清零 取反/置位111(模式7)清零/置位当主计数器计到TACCRx时,TAx管脚取0 当主计数器计到TACCR0时,TAx管脚置179 有用的MCx+OUTMODx? 虽然MCx+OUTMODx的排列组合将有24种,但是只有几种组合是“有用 的”,用于生成以下4种特定波形:80 单稳态脉冲? 增计数81 普通PWM? 增计数模式82 死区PWM? 增减计数83 三路方波? 增计数84 3.13 input 与output? INPUT远比OUTPUT复杂!? 判断输入的程序极易造成CPU阻塞。IO Port入门必备Input从车站接人某酒店服务送站80元,接站120元Output送人去车站按键识别被动接收数据被动翻转IO电平主动发送数据主动85 3.14 机械按键的中断识别方法? 在一次按键过程中,会有若干次下降沿,只有1是真正的按键事件。? 如图所示的按键过程中,会引发5次中断。 ? 检测到下降沿1和4后,关闭中断,用延时可以消灭2、3、5。 ? 1延时后,电平仍然是0,4延时后,电平会变成1。据此用if语句可判断 出4不是按下,而是弹起的毛刺。86 void P1_IODect() { unsigned int Push_Key=0; Push_Key=P1IFG&(~P1DIR); //代码1:检测所有输入IO,确保只有1个IO中断被“记录” //----延时一段时间,避开机械抖动区域-----__delay_cycles(10000); //代码2:消灭下降沿2、3、5 //----判断按键状态是否与延时前一致-----if((P1IN&Push_Key)==0) //代码3:专门消灭下降沿4 { //----判断具体哪个IO被按下,调用该IO的事件处理函数 switch(Push_Key) { case BIT0: P10_Onclick(); case BIT1: P11_Onclick(); case BIT2: P12_Onclick(); case BIT3: P13_Onclick(); case BIT4: P14_Onclick(); case BIT5: P15_Onclick(); case BIT6: P16_Onclick(); case BIT7: P17_Onclick(); default: } }87 3.15 定时中断扫描法实现机械按键识别? MSP-EXP430G2开发板上P1.3接了一个按键,P1.0和P1.6接了LED(用 跳线帽连接),下面我们将编写一段代码,每次按下P1.3后,两个LED1 亮1灭交换亮灭状态。88 前后台任务结构休眠后台任务While(1) 事件检测前台任务事件处理最难的是事件检测!89 事件检测函数 P1_IODect()? 利用WDT定时器周期性的产生中断。? 在中断子函数中,判断IO电平即可知道按键是否按下或弹起。 ? 只要满足WDT时间大于毛刺持续时间,小于按键持续时间,自动消抖。90 void P1_IODect() { 主函数 static unsigned char KEY_Now=0; //变量值出函数时需保留 void mian() unsigned char KEY_Past=0; KEY_Past=KEY_N 中断服务子 休眠 //-----查询IO的输入寄存器----函数 WDT_ISR() LPM3 if(P1IN&BIT3) KEY_Now=1; else KEY_Now=0; 事件检测函 //-----前一次高电平、后一次低电平,说明按键按下----数 if((KEY_Past==1)&&(KEY_Now==0)) P1_IODect() P13_Onclick(); 事件处理函 }数P13_Onclick()IO初始化函 数GPIO_Init()WDT初始化 函数WDT_init()91 主函数#include &MSP430G2553.h&主函数//-----在main函数前提前声明函数----void P1_IODect(); void P13_Onclick(); void GPIO_init(); void WDT_init(); void main(void) { WDTCTL = WDTPW + WDTHOLD; //关狗 GPIO_init(); WDT_init(); _enable_interrupts(); //开总中断 _bis_SR_register(LPM3_bits); //LPM3休眠 }void mian()中断服务子 函数WDT_ISR()休眠LPM3事件检测函 数P1_IODect()事件处理函 数P13_Onclick()IO初始化函 数GPIO_Init()WDT初始化 函数WDT_init()92 初始化函数GPIO_Init()/****************************************************************************************************** * 名 称:GPIO_Init() 主函数 * 功 能:设定按键和LED控制IO的方向,启用按键IO的上拉电阻 void mian() *************************************************************************/ void GPIO_init() 中断服务子 休眠 { 函数 WDT_ISR() LPM3 //-----设定P1.0和P1.6的输出初始值----P1DIR |= BIT0+BIT6; //设定P1.0和P1.6为输出 事件检测函 P1OUT |= BIT0; //设定P1.0初值 数 P1OUT &= ~BIT6; //设定P1.6初值 P1_IODect() //-----配合机械按键,启用内部上拉电阻----事件处理函 P1REN |= BIT3; //启用P1.3内部上下拉电阻 数 P1OUT |= BIT3; //将电阻设置为上拉 P13_Onclick() //-----不再使用P1.3中断功能----//P1DIR &= ~BIT3; // P1.3设为输入(可省略) IO初始化函 WDT初始化 //P1IES |= BIT3; // P1.3设为下降沿中断 数 函数 GPIO_Init() WDT_init() //P1IE |= BIT3 ; // 允许P1.3中断 } 93 初始化函数WDT_init()/****************************************************************************************************** * 名 称:WDT_init() 主函数 * 功 能:设定WDT定时中断为16ms,开启WDT定时中断使能 void mian() * 说 明:WDT定时中断的时钟源选择ACLK,可以用LPM3休眠。 ************************************************************/ 中断服务子 休眠 void WDT_init() 函数 WDT_ISR() LPM3 { //-----设定WDT为16ms中断----事件检测函 WDTCTL = WDT_ADLY_16; 数 P1_IODect() //-----WDT中断使能----IE1 |= WDTIE; 事件处理函 }数P13_Onclick()IO初始化函 数GPIO_Init()WDT初始化 函数WDT_init()94 中断服务函数WDT_ISR()/****************************************************************************************************** * 名 称:WDT_ISR() 主函数 * 功 能:响应WDT定时中断服务 void mian() *****************************************************************/ #pragma vector=WDT_VECTOR 中断服务子 休眠 函数 __interrupt void WDT_ISR(void) WDT_ISR() LPM3 { //-----启用Port1事件检测函数----事件检测函 P1_IODect(); //检测通过,则会调用事件处理函数 数 P1_IODect() }事件处理函 数P13_Onclick()IO初始化函 数GPIO_Init()WDT初始化 函数WDT_init()95 事件处理函数P13_Onclick()/****************************************************************************************************** * 名 称:P13_Onclick() 主函数 * 功 能:P1.3的中断事件处理函数,即当P1.3键被按下后, void mian() 下一步干什么 * 说 明:使用事件处理函数的形式, 中断服务子 休眠 函数 可以增强代码的移植性和可读性 WDT_ISR() LPM3 ***********************************************************/ void P13_Onclick() //P1.3的事件处理函数 事件检测函 { 数 P1_IODect() //----翻转IO电平----P1OUT ^= BIT0; 事件处理函 P1OUT ^= BIT6; 数 P13_Onclick() }IO初始化函 数GPIO_Init()WDT初始化 函数WDT_init()96 练习3.1:用前后台程序写法实现按键检测? 编写一个按键检测函数, 自行决定P1.3按键按下和 按键松开后,两个LED做 出何反应。? 要求用前后台程序结构编 写程序 ? 使用初始化函数主函数void mian()中断服务子 函数WDT_ISR()休眠LPM3事件检测函 数P1_IODect()? 使用事件检测函数? 使用事件处理函数 ? 使用LPM3低功耗休眠事件处理函 数P13_Onclick()事件处理函 数P13_Onrelease()IO初始化函 数GPIO_Init()WDT初始化 函数WDT_init()97 3.16 定时中断扫描法实现机械按键长短键识别? 对于前后台程序,事件的发生就有对应解决方案。? 长度按键事件的判断不仅与当前输入(事件)有关,还与之前的“积累 效应”(状态)有关。 ? 这类非常普遍事件的检测需要用到传说中的“状态机”。有限状态下发生事 件两大要素决定该干 什么状态机状态事件两种方法均有效检测事件米利状态 机查询状态摩尔状态 机98 状态机的建模方法99 状态中判断事件//---------状态中查询事件(Mealy状态机)----------switch(State) { case 0: if(Event_0) Action2(); //路径1 if(Event_1) {State=2; Action0();} //路径3 if(Event_2) State=2; //路径4 case 1: if(Event_0) State2; //路径5 if(Event_2) {State=0; Action2();} //路径2 case 2: if(Event_1) {State=1; Action1(); } //路径6 default: }100 事件中查询状态//---------状态中查询事件(Moore状态机)----------if(Event0) { //中断或扫描得知Event0事件发生 switch(State){ case 0: Action2(); //路径1 case 1: State=2; //路径5 default:} } if(Event1) {//中断或扫描得知Event1事件发生 switch(State){ case 0: State=2; Action0(); //路径3 case 2: State=1; Action1(); //路径6 default:} } if(Event2) {//中断或扫描得知Event2事件发生 switch(State) { case 0: State=2; //路径4 case 1: State=0; Action2(); //路径2 default: } }101 例程:长短按键的识别? 短按P1.3控制LED1的亮灭,长按P1.3控制LED2的亮灭。102 画出状态转换图穷举所有 状态穷举所有 事件合并重复状态103 状态机程序建模状态机 函数主函数void mian()后台 程序初始化 函数中断服务子 函数WDT_ISR()休眠LPM3事件 处理状态机函数Key_SM()按键按下事 件前高后低事件 检测长按键事件处理函数P13_OnLongClick()短按键事件处理函 数P13_OnShortRelease()按键松开事 件前低后高长按键检测函数LongClick_Dect()IO初始化函 数GPIO_Init()WDT初始化 函数WDT_init()104 主函数主函数void mian()中断服务子 函数WDT_ISR()休眠LPM3状态机函数Key_SM()按键按下事 件前高后低长按键事件处理函数P13_OnLongClick()短按键事件处理函 数P13_OnShortRelease()按键松开事 件前低后高长按键检测函数LongClick_Dect()()IO初始化函 数GPIO_Init()WDT初始化 函数WDT_init()105 主函数#include &MSP430G2553.h& //-----对状态机进行宏定义----#define IDLE 0 #define SHORT 1 #define LONG 2 #define COUNTER_THRESHOLD 50/*长键判别门限*/ //-----全局变量----unsigned char WDT_Counter=0; /*用于对按键按下时间进行计数*/ //-----在main函数前提前声明函数----void GPIO_init(); void WDT_init(); void Key_SM(); unsigned char LongClick_Dect(); void P13_OnShortRelease(); void P13_OnLongClick(); void main(void) { WDTCTL = WDTPW + WDTHOLD; //关狗 GPIO_init(); WDT_init(); _enable_interrupts(); //开总中断 _bis_SR_register(LPM3_bits); //LPM3休眠 }106 初始化函数GPIO_init()中断服务子 函数WDT_ISR()主函数void mian()休眠LPM3状态机函数Key_SM()按键按下事 件前高后低长按键事件处理函数P13_OnLongClick()短按键事件处理函 数P13_OnShortRelease()按键松开事 件前低后高长按键检测函数LongClick_Dect()IO初始化函 数GPIO_Init()WDT初始化 函数WDT_init()107 初始化函数GPIO_init()/******************************************************************* * 名 称:GPIO_init() * 功 能:设定按键和LED控制IO的方向,启用按键IO的上拉电阻 *****************************************************************/ void GPIO_init() { //-----设定P1.0和P1.6的输出初始值----P1DIR |= BIT0+BIT6;//设定P1.0和P1.6为输出 P1OUT |= BIT0; //设定P1.0初值 P1OUT &= ~BIT6; 用内部上拉电阻----P1REN |= BIT3; //启用P1.3内部上下拉电阻 P1OUT |= BIT3; //将电阻设置为上拉 }108 初始化函数WDT_init()中断服务子 函数WDT_ISR()主函数void mian()休眠LPM3状态机函数Key_SM()按键按下事件前高后低长按键事件处理函数P13_OnLongClick()短按键事件处理函数P13_OnShortRelease()按键松开事件前低后高长按键检测函数LongClick_Dect()IO初始化函 数GPIO_Init()WDT初始化 函数WDT_init()109 初始化函数WDT_init()? WDT设为16ms定时。? 保证短于手按键的时长,而大于毛刺的时长。 ? 其他WDT定时都不合适,1.9ms太短,250ms太长。/***************************************************************** * 名 称:WDT_init() * 功 能:设定WDT定时中断为16ms,开启WDT定时中断使能 * 说 明:WDT定时中断的时钟源选择ACLK,可以用LPM3休眠。 ***************************************************************/ void WDT_init() { //-----设定WDT为----WDTCTL=WDT_ADLY_16; //-----WDT中断使能----IE1|=WDTIE; }110 中断服务函数WDT_ISR()主函数void mian()中断服务子 函数WDT_ISR()休眠LPM3状态机函数Key_SM()按键按下事 件前高后低长按键事件处理函数P13_OnLongClick()短按键事件处理函 数P13_OnShortRelease()按键松开事 件前低后高长按键检测函数LongClick_Dect()IO初始化函 数GPIO_Init()WDT初始化 函数WDT_init()111 中断服务函数WDT_ISR()? 在WDT定时节拍中,启用状态机来判断事件。/*************************************** * 名 称:WDT_ISR() * 功 能:响应WDT定时中断服务 * 说 明:不能直接判断事件,需启用状态机 **************************************/ #pragma vector=WDT_VECTOR __interrupt void WDT_ISR(void) { //-----启用按键状态机----Key_SM(); }112 状态机函数Key_SM()主函数void mian()中断服务子 函数WDT_ISR()休眠LPM3状态机函数Key_SM()按键按下事 件前高后低长按键事件处理函数P13_OnLongClick()短按键事件处理函 数P13_OnShortRelease()按键松开事 件前低后高长按键检测函数LongClick_Dect()IO初始化函 数GPIO_Init()WDT初始化 函数WDT_init()113 Mealy状态机函数Key_SM()/********************************************************************** * 名 称:Key_SM() * 功 能:判断出长短键 * 说 明:本状态机为Mealy型状态机,在Switch(State)中需要判断事件 ***************************************************************************/ void Key_SM() { static unsigned char State=0; //状态机的状态变量 static unsigned char Key_Now=0; //记录按键的当前电平 unsigned char Key_Past=0; //记录按键的前一次电平 unsigned char Key_Dect=0; //按键状态值 Key_Past=Key_N //-----查询IO的输入寄存器----if(P1IN&BIT3) Key_Now=1; else Key_Now=0; //-----电平前高后低,表明按下----if((Key_Past==1)&&(Key_Now==0)) Key_Dect=1;114 Mealy状态机函数Key_SM()//-----电平前低后高,表明弹起----if((Key_Past==0)&&(Key_Now==1)) Key_Dect=2 ; switch(State)//该状态机靠扫描的按键值Key_Dect跳转状态 { case IDLE: WDT_Counter=0; //空闲状态对计数清零 if(Key_Dect==1) State=SHORT; //路径1 case SHORT: if(Key_Dect==2) { //路径2 State=IDLE; P13_OnShortRelease(); } //短按事件处理函数 if(LongClick_Dect()){ //路径3 State=LONG; P13_OnLongClick(); } //长按事件处理函数case LONG: WDT_Counter=0; //长按状态对计数清零 if(Key_Dect==2) State=IDLE; //路径4 default: State=IDLE; } }115 Moore状态机函数Key_SM()/******************************************************************************************************* 名 称:Key_SM() * 功 能:长短键状态机 * 说 明:本状态机为Moore型状态机,在Switch(State)中无需判断事件 **************************************************************************/ void Key_SM() { static unsigned char State=0; //状态机的状态变量 static unsigned char Key_Now=0; //记录按键的当前电平 unsigned char Key_Past=0; //记录按键的前一次电平 Key_Past=Key_N //-----查询IO的输入寄存器----if(P1IN&BIT3) Key_Now=1; else Key_Now=0;116 Moore状态机函数Key_SM()/******************************************************************************************************//-----电平前高后低,表明按键按下事件----if((Key_Past==1)&&(Key_Now==0)) { switch(State) { case IDLE:WDT_Counter=0;State=SHORT; //路径1 default: } }117 Moore状态机函数Key_SM()//-----电平前低后高,表明按键松开----if((Key_Past==0)&&(Key_Now==1)) { switch(State) { case SHORT:State=IDLE;P13_OnShortRelease(); //路径2 case LONG:WDT_Counter=0;State=IDLE; //路径4 default: } }118 Moore状态机函数Key_SM()if(LongClick_Dect()) { switch(State) { case SHORT:State=LONG;P13_OnLongClick(); //路径3 default: } } }119 事件检测函数LongClick_Dect()? 长按键的检测原理是计时, 超过某一时长即判定为长键 。? 时长的单位选择为WDT定时 (周期)值。中断服务子 函数WDT_ISR()主函数void mian()休眠LPM3状态机函数Key_SM()按键按下事 件前高后低长按键事件处理函数P13_OnLongClick()短按键事件处理函 数P13_OnShortRelease()按键松开事 件前低后高? 计时的其他前提条件,例如 必须是按键按下时才开始计 时,这些都交给状态机去处 理。长按键检测函数LongClick_Dect()IO初始化函 数GPIO_Init()WDT初始化 函数WDT_init()120 事件检测函数LongClick_Dect()/****************************************************************************************************** * 名 称:LongClick_Dect() * 功 能:对WDT中断计时,计满清零并返回”长键“信息 * 出口参数:1:长按键;0:非长按键 ******************************************************************************************************/ unsigned char LongClick_Dect() { WDT_Counter++; if (WDT_Counter==COUNTER_THRESHOLD) { WDT_Counter=0; return(1); } else return(0); }121 事件函数中断服务子 函数WDT_ISR()主函数void mian()休眠LPM3状态机函数Key_SM()按键按下事 件前高后低长按键事件处理函数P13_OnLongClick()短按键事件处理函 数P13_OnShortRelease()按键松开事 件前低后高长按键检测函数LongClick_Dect()IO初始化函 数GPIO_Init()WDT初始化 函数WDT_init()122 事件函数/********************************************************************** * 名 称:P13_OnShortRelease() * 功 能:P1.3的短按事件处理函数,即当P1.3键被”短按“后,下一步干什么 * 说 明:使用事件处理函数的形式,可以增强代码的移植性和可读性 *****************************************************************************/ void P13_OnShortRelease() //P1.3的事件处理函数 { P1OUT ^= BIT0; //----翻转P1.3IO电平----} /***************************************************************************** * 名 称:P13_OnLongClick() * 功 能:P1.3的长按事件处理函数,即当P1.3键被”长按“后,下一步干什么 ***********************************************************************************************/ void P13_OnLongClick() //P1.3的事件处理函数 { P1OUT ^= BIT6; //----翻转P1.6IO电平----}123 练习3.2:用状态机程序写法实现长短按键检测? 编写一个长短按键按 键检测函数,自行决 定长短按键后,两个 LED做出何反应。? 要求用状态机程序结 构编写程序 ? 分别用米利状态机和 摩尔状态机方法实现 ? 全部的事件都独立编 写函数。 ? 使用LPM3低功耗休眠 。主函数void mian()中断服务子 函数WDT_ISR()休眠LPM3状态机函数Key_SM()按键按下事 件前高后低长按键事件处理函数P13_OnLongClick()短按键事件处理函 数P13_OnShortRelease()按键松开事 件前低后高长按键检测函数LongClick_Dect()()IO初始化函 数GPIO_Init()WDT初始化 函数WDT_init()124 第4讲 自校验DCO频率青岛大学-美国德州仪器MSP430单片机共建实验室傅强125 4.1 普林斯顿结构? 普林斯顿结构处理器的RAM和ROM统一编址,共用地址总线和数据总线 。126 4.2 Flash存储器FLASHSRAMNANDNOR随便读随便写读一个扇 区擦写一个 扇区随便读擦写一段127 4.3 Flash 控制器? 对Flash进行读操作无需任何硬件支持,就是读普通ROM。? 对Flash写操作需要MSP430内部集成了Flash控制器。 ? Flash编程时钟:写太快不可靠,写太慢寿命低。128 ? Flash编程高压发生器? 擦鞋Flash需要比读取Flash更高的电压。 ? 如图是Flash按字节写入时序过程。129 4.4 利用Flash进行掉电不失存储? 整段擦除为 “1” ? 擦前备份 ? 按字节写为 “0” ? 重复写无效擦备份原 数据段写擦除全 段数据 写入目 标数据 还原其 他数据130 4.5 Flash操作库函数全局变量SegAddr,SegPre初始化函数段擦除函数Flash_Init( )Flash_Erase()直接写字函数 Flash_Direct_WriteWord()备份写字节函数 Flash_Bak_WriteChar()131 初始化函数Flash_Init( )/****************************************************************************************************** *名 称:Flash_Init() *功 能:对Flash时钟进行初始化设置 * 入口参数:Div:根据SMCLK频率计算的所需分频值,可设定为1-64 * Seg:段号,可设为&0&-&31&或”&A&、&B&、&C&、&D&。 * 出口参数:1:配置成功 * 0:配置失败 * 说 明:操作Flash其他函数前,需要调用该初始化函数设置时钟分频和待操作段首地址。 * 其他函数中均不出现绝对地址,防止误操作。 * 范 例: Flash_Init(3,'B' ) 3分频、对Info B段操作 ******************************************************************************************************/ unsigned char Flash_Init(unsigned char Div,unsigned char Seg ) { //-----设置Flash的时钟和分频,分频为恰好为最低位,直接用Div-1即可----if(Div&1) Div=1; if(Div&64) Div=64; FCTL2 = FWKEY + FSSEL_2 + Div-1; // 默认使用SMCLK,分频系数参数传入132 初始化函数Flash_Init( )//-----操作对象为主Flash段的情况,可通过512的倍数设置段起始地址----SegPre = S //获取当前段 if (Seg &= 31) //判断是否处于主Flash段 { SegAddr=0xFFFF-(Seg+1)*512+1; //计算段起始地址 return(1); //赋值成功后即可退出并返回成功标志”1“ } //-----操作对象为信息Flash段的情况,穷举即可----switch(Seg) //判断是否处于信息Flash段 { case 'A': case'a': SegAddr=0x10C0; case 'B': case'b': SegAddr=0x1080; case 'C': case'c': SegAddr=0x1040; case 'D': case'd': SegAddr=0x1000; default: SegAddr=0x20FF; return(0); //0x20FF地址为空白区,保护Flash } return(1); }133 擦除函数Flash_Erase()* 名 称:Flash_Erase() * 功 能:擦除Flash的一个数据块,擦写段由初始化函数 Flash_Init()的SegAddr变量决定 ******************************************************************************************************/ void Flash_Erase() { unsigned char *Ptr_SegA //Segment pointer Ptr_SegAddr = (unsigned char *)SegA //Initialize Flash pointer FCTL1 = FWKEY + ERASE; //段擦除模式 FCTL3 = FWKEY; //解锁 //FCTL3 = FWKEY+LOCKA; //对InfoFlashA也解锁 _disable_interrupts(); *Ptr_SegAddr = 0; //擦除待操作段 while(FCTL3&BUSY); //Busy _enable_interrupts(); FCTL1 = FWKEY; //取消擦模式 FCTL3 = FWKEY+LOCK; //上锁 // FCTL3 = FWKEY+LOCK+LOCKA; //对InfoFlashA也上锁 } 134 Flash_Direct_WriteWord()/****************************************************************************************************** * 名 称:Flash_Direct_WriteWord() * 功 能:强行向Flash中写入一个字型变量,而不管存储位置是否事先擦除 * 入口参数:Addr:存放数据的偏移地址,仍按字节计算,需为偶数 Data:待写入的数据 * 出口参数:返回出错信息 0:偏移溢出 ;1:正常工作 * 范 例:Flash_Direct_WriteWord(0,123);将常数123写入0单元 Flash_Direct_WriteWord(2,a);将整型变量a写入2单元 ******************************************************************************************************/ char Flash_Direct_WriteWord (unsigned int Addr,unsigned int Data) { unsigned int temp=0; unsigned int *Ptr_SegA //Segment pointer //----- 段范围限定。为了内存管理安全,只允许本段操作----if((SegPre&=31&&Addr&=512) ||(SegPre&31&&Addr&=64) ) return 0;135 Flash_Direct_WriteWord()return 0; temp=SegAddr+A Ptr_SegAddr = (unsigned int *) //Initialize Flash pointer FCTL1=FWKEY+WRT; //正常写状态 FCTL3=FWKEY; //解除锁定 FCTL3=FWKEY+LOCKA; //解除锁定(包括A段) _disable_interrupts(); //关总中断 *Ptr_SegAddr=D while(FCTL3&BUSY); //等待操作完成 _enable_interrupts(); //开总中断 FCTL1=FWKEY; //退出写状态 FCTL3=FWKEY+LOCK; //恢复锁定,保护数据 FCTL3=FWKEY+LOCK+LOCKA; //恢复锁定,保护数据(包括A段) return 1;////}136 备份擦写字节函数Flash_Bak_WriteChar()/****************************************************************************************************** * 名 称:Flash_Bak_WriteChar() * 功 能:不破坏段内其他数据,向Flash中写入一个字节(Char型变量) * 入口参数:Addr:存放数据的地址 Data:待写入的数据 * 出口参数:返回出错信息 0:偏移溢出 ;1:正常工作 * 范 例:Flash_Bak_WriteChar(0,123);将常数123写入0单元 Flash_Bak_WriteChar(1,a);将变量a写入1单元 ******************************************************************************************************/ char Flash_Bak_WriteChar (unsigned char Addr,unsigned char Data) { unsigned int temp=0; unsigned char *Ptr_SegA //Segment pointer unsigned char BackupArray[64]; //开辟64字节的临时RAM备份Seg unsigned char i = 0; //----- 段范围限定。为了内存管理安全,只允许本段操作----if((SegPre&=31&&Addr&=512) || (SegPre&31&&Addr&64) ) 137 return 0; 备份擦写字节函数Flash_Bak_WriteChar()for(i=0;i&64;i++) { temp=SegAddr+i; Ptr_SegAddr = (unsigned char *) //Initialize Flash pointer BackupArray[i]=*Ptr_SegA //指针移位方法赋值 } Flash_Erase(); //擦除待操作段 FCTL1 = FWKEY + WRT; //正常写入(非块写) FCTL3 = FWKEY ; //解锁 FCTL3 = FWKEY ; //解锁(含A段) for (i=0; i&64; i++) { _disable_interrupts(); //关总中断 if(i==Addr) { temp=SegAddr+A138// 备份擦写字节函数Flash_Bak_WriteChar()Ptr_SegAddr = (unsigned char *) //Initialize Flash pointer *Ptr_SegAddr =D //写数据 while(FCTL3&BUSY); //等待写操作完成 } else { temp=SegAddr+i; Ptr_SegAddr = (unsigned char *) //Initialize Flash pointer *Ptr_SegAddr = BackupArray[i]; //恢复Flash内的其他数据 while(FCTL3&BUSY); //等待写操作完成 } _enable_interrupts(); //开总中断 } FCTL1 = FWKEY; //清除写 FCTL3 = FWKEY + LOCK; //上锁 // FCTL3 = FWKEY + LOCK; //上锁(含A段) return 1;}139 4.6 DCO测频原理f DCO ? 25535 /16ms ? 1596kHz ? 1.6MHz140 4.7 VLO测频原理? 基于上次TAR值25535我们可以求得:fVLO ? 32.768kHz ? (25535 / 45535) ? 18.376 kHz141 4.8 自校验DCO输出频率f? 穷举DCO参数设置,测出实际频率,即可完成校验。? 4位RSELx:16个档位,每档频率步进约35%(不靠谱),可看成粗调 。 ? 3位DCOx:8个档位,每档频率步进约8%(不靠谱),可看成细调。DCO x ?1 ? DCO x ? 5位MODx:32个档位,每档步进 ,可看成微调。 32142 确定RSELx与DCOx? 得到全部Temp[]数据后,找出最接近f但小于的f的temp[i]? 比如是Temp[35],这样我们就知道了RSELx=35/8=4,DCOx=35%8=3 。MODx=0 ? 先不微调 RSELx ? DCOx ? 共128种组 合 测出所有频率 ? WDT定时 ? TA计数 存入Temp[i] ? 由i可反推出 ? RSELx ? DCOx143 确定MODx? 固定RSELx=4、DCOx=3,依次增加MODx的值,找到最接近f时的 MODx值,比如说是12。? 那么f对应的DCO参数就是RSELx=4、DCOx=3、 MODx=12。 ? 仿照出厂校验的做法,将3个参数存在infoFLash中。RSELx=4 ? DCOx=3递增MODx ? 共32种值测出所有频率 ? WDT定时 ? TA计数找到MODx ? 存入 infoFlash144 4.9 自校验DCO例程? 自校准1-16MHz共16个DCO配置参数(RSELx,DCOx,MODx),将 参数写入InfoFlashB段中,调取校验参数,循环输出DCO的16个频率供 观测。145 主函数void main(void) { WDTCTL = WDTPW + WDTHOLD; //关狗 //-----在P1.4上输出SMCLK,这样可以全程用示波器和频率计观测DCO---P1SEL |= BIT4; P1DIR |= BIT4; //-----初始化TA,开启WDT中断使能----TA0CTL = TASSEL_2+MC_2+TACLR; // SMCLK时钟源,连续计数开始 IE1|=WDTIE; //开启WDT中断 _enable_interrupts(); //等同_ENT,开启总中断 //-----开始DCO频率校验,只运行一遍----Calibrate_Start(); //步骤1:红灯亮,表示正在校验DCO Measure_Temp(); //步骤2:自动测量128个纯净频率 Find_RSELx_DCOx_Winer(); //步骤3:从128个纯净频率中,找出最接近预设频率的那几个 Measure_MODx(); //步骤4:在最近接的纯净频率基础上,穷举找到最优的MODx设置 Calculate_InfoFlash_Data(); //步骤5:将最合适的频率设定参数组合成校验数组 Write_InfoFlashB(); //步骤6:将校验数组写入InfoFlahB段 Calibrate_Finish(); //步骤7:绿灯亮,表示完成校验DCO //-----完成DCO校验,从Flash中定时取出校准值,从P1.4输出供测试----146 DCOTest(); //步骤8:循环输出DCO各个校验频率值,供观测 } 1、点亮红灯 Calibrate_Start();2、测量128个“纯 净”DCO频率3、找出最接近的 16个“纯净”频率 Find_RSELx_DC Ox_Winer();Measure_Temp();6、写入Flash Write_InfoFlashB( )5、合成校验数组 Calculate_InfoFlas h_Data()4、找出最优 MODx Measure_MODx()7、点亮绿灯 Calibrate_Finish();8、循环输出DCO DCOTest()流水账作业147 变量和宏定义? 注意(x)的写法,实现宏定义“传参”操作。 ? Temp[](不带MODx)和Ture_Freq[](带MODx)存储的都是实际测量 的频率值#include &MSP430G2553.h& #include &Flash.h& #define CALDCO_MHz(x) * (unsigned char *)(0x1080+(x-1)*2) /*读取InfoFlashB*/ #define CALBC1_MHz(x) * (unsigned char *)(0x1080+(x-1)*2+1) #define CAL_NUM 16 /*待校验频率点总数*/ unsigned int Temp[128]={0}; /*存放实测的128个不含小数分频MODx的“纯净”频率*/ unsigned char RSELx_DCOx_Winer[CAL_NUM]={0}; /*存放校验出的SELx和DCOx值*/ unsigned char MODx_Winer[CAL_NUM]={0}; /*存放校验出的MODx值*/ unsigned int InfoFlash_Data[CAL_NUM]={0}; /*待写入infoB中的校验频率参数数组*/ unsigned int Ture_Freq[CAL_NUM]={0}; /*方便仿真时查看实测频率值*/ // -----待校正的频率,单位KHz----const unsigned int Calibrate_Frequence[CAL_NUM]={00,00, 00,,,,16000};148 1、点亮红灯 Calibrate_Start();2、测量128个“纯 净”DCO频率3、找出最接近的 16个“纯净”频率 Find_RSELx_DC Ox_Winer();Measure_Temp();6、写入Flash Write_InfoFlashB( )5、合成校验数组 Calculate_InfoFlas h_Data()4、找出最优 MODx Measure_MODx()7、点亮绿灯 Calibrate_Finish();循环输出DCO DCOTest()流水账作业149 开始指示函数Calibrate_Start()? 在很多时候,一个小小的LED可以给程序调试乃至设备维护,故障排查 带来很大方便。? 本例中,红色LED亮表示校验正在进行。/****************************************************************************************************** * 名 称:Calibrate_Start() * 功 能:红色LED亮,表明正在校验中 * 说 明:DCO校验的时间比较长,利用红灯指示可以方便调试程序 ******************************************************************************************************/ void Calibrate_Start() //步骤1:红灯亮,表示正在校验DCO { P1DIR |=BIT0+BIT6; P1OUT |= BIT0; //红亮绿灭表示正在校验 P1OUT &=~BIT6; }150 1、点亮红灯 Calibrate_Start();2、测量128个“纯 净”DCO频率3、找出最接近的 16个“纯净”频率 Find_RSELx_DC Ox_Winer();Measure_Temp();6、写入Flash Write_InfoFlashB( )5、合成校验数组 Calculate_InfoFlas h_Data()4、找出最优 MODx Measure_MODx()7、点亮绿灯 Calibrate_Finish();循环输出DCO DCOTest()流水账作业151 测频函数Measure_Temp()* 名 称:Measure_Temp() * 功 能:自动依次测定128种纯净DCO的频率,并存入Temp[]数组 * 说 明:纯净频率是指MOD=0时的非混频 ******************************************************************************************************/ void Measure_Temp() { //步骤2:自动测量128个纯净频率 unsigned long Freq_Temp=0; unsigned char RSELx_DCOx_Num=0; for(RSELx_DCOx_Num=0;RSELx_DCOx_Num&128;RSELx_DCOx_Num++) { DCO_Set_Freq(RSELx_DCOx_Num,0); //-----定时测频代码开始----TA0CTL |=TACLR; //计数开始 WDTCTL=WDT_ADLY_1_9;//WDT定时长度为精心选择过的,20MHz计数到39063 _bis_SR_register(LPM0_bits); //CPU精确休眠1.9ms(1/512秒) WDTCTL=WDTPW+WDTHOLD; Freq_Temp = TA0R; //读取计数,这个值就是DCO在1/512秒中断区间的脉冲数 //-----定时测频代码结束----Temp[RSELx_DCOx_Num]=((Freq_Temp)*512)/1000; } } //计算DCO准确频率152 配置DCO的函数DCO_Set_Freq()/****************************************************************************************************** * 名 称:DCO_Set_Freq() * 功 能:根据传入参数,设定DCO频率 * 入口参数:Num:Num的0~2位表示DCOx,3~6位表示RSELx modTemp:MODx参数 * 说 明:Num参数身兼二职,包含DCOx和RSELx的信息 * 范 例:DCO_Set_Freq(10,5),表示将DCO设定为RSELx=1,DCOx=2,MODx=5 ******************************************************************************************************/ void DCO_Set_Freq(unsigned char Num,unsigned char modTemp) //参数设定DCO频率 { DCOCTL = ((Num%8)&&5)+modT //数据拆分 BCSCTL1 &=~0x0F; BCSCTL1 |=Num/8; __delay_cycles(15000); //等待DCO频率稳定 }153 WDT定时中断服务子函数? WDT定时中断仅起到了延时唤醒的作用。/****************************************************************************************************** * 名 称:WDT_ISR() * 功 能:响应WDT定时中断服务 * 说 明:程序内部只有1句唤醒CPU代码,这种写法即用到了WDT的定时功能,同时避免将 * 大量代码写入中断服务函数中,影响程序的可读性。 ******************************************************************************************************/ #pragma vector=WDT_VECTOR __interrupt void WDT_ISR(void) { __bic_SR_register_on_exit(LPM0_bits ); //退出中断时,唤醒CPU }154 1、点亮红灯 Calibrate_Start();2、测量128个“纯 净”DCO频率3、找出最接近的 16个“纯净”频率 Find_RSELx_DC Ox_Winer();Measure_Temp();6、写入Flash Write_InfoFlashB( )5、合成校验数组 Calculate_InfoFlas h_Data()4、找出最优 MODx Measure_MODx()7、点亮绿灯 Calibrate_Finish();循环输出DCO DCOTest()流水账作业155 比较函数Find_RSELx_DCOx_Winer()/****************************************************************************************************** * 名 称:Find_RSELx_DCOx_Winer() * 功 能:从128个Temp[]中,找出与16个校验频率最接近的Temp的序号 * 说 明:Temp的序号里包含了RSELx和DCOx的取值信息 ******************************************************************************************************/ void Find_RSELx_DCOx_Winer() //步骤3:从128个纯净频率中,找出最接近d的预设频 { unsigned char i=0; unsigned int Delta_Min=0; unsigned int Delta_Now=0; unsigned char Calibrate_Num=0; for(Calibrate_Num=0;Calibrate_Num&CAL_NUM;Calibrate_Num++) { Delta_Min=65530; //第一次比较时,故意定一个大差值156 比较函数Find_RSELx_DCOx_Winer()for(i=0;i&128;i++) { //-----单方向取最小差值,一定要小于预设值----if(Temp[i]&Calibrate_Frequence[Calibrate_Num]) { Delta_Now=Calibrate_Frequence[Calibrate_Num]-Temp[i]; if (Delta_Now&Delta_Min) //如果当前差值比“世界记录”还小时 { RSELx_DCOx_Winer[Calibrate_Num]=i; //新Winner诞生 Delta_Min=Delta_N //取代前“世界记录” } } }} }157 1、点亮红灯 Calibrate_Start();2、测量128个“纯 净”DCO频率3、找出最接近的 16个“纯净”频率 Find_RSELx_DC Ox_Winer();Measure_Temp();6、写入Flash Write_InfoFlashB( )5、合成校验数组 Calculate_InfoFlas h_Data()4、找出最优 MODx Measure_MODx()7、点亮绿灯 Calibrate_Finish();循环输出DCO DCOTest()流水账作业158 测频比较函数Measure_MODx()/****************************************************************************************************** * 名 称:Measure_MODx() * 功 能:基于已校验成功的RSELx和DCOx,进一步校验出最合适的MODx * 说 明:本函数将固定RSELx和DCOx,穷举32种MODx的取值,然后判断最优的MODx ******************************************************************************************************/ void Measure_MODx() //步骤4:在最近接的纯净频率基础上,穷举找到最优的MODx设置 { unsigned char mod_x = 0; unsigned long Freq_Temp = 0; unsigned int Delta_Now=0; unsigned int Delta_Min=0; unsigned char Calibrate_Num=0; for(Calibrate_Num=0;Calibrate_Num&CAL_NUM;Calibrate_Num++) { Delta_Min=65530; //第一次比较时,故意定一个大差值159 测频比较函数Measure_MODx()//-----RSELx和DCOx一定时,测量mod_x改变时的系列频率----for(mod_x=0;mod_x &32;mod_x++){ DCO_Set_Freq(RSELx_DCOx_Winer[Calibrate_Num],mod_x);//改变mod_x设置DCO //-----定时测频代码开始----TA0CTL |=TACLR; WDTCTL=WDT_ADLY_1_9; _bis_SR_register(LPM0_bits ); //CPU精确休眠1.9ms(1/512秒) WDTCTL=WDTPW+WDTHOLD; Freq_Temp = TA0R; //读取&测频&值 //-----定时测频代码结束----Freq_Temp=((Freq_Temp)*512)/1000; //计算DCO准确频率 //-----与Find_RSELx_DCOx_Winer()不同,这里的要求是正负差值最小----if(Freq_Temp&Calibrate_Frequence[Calibrate_Num]){ Delta_Now=Calibrate_Frequence[Calibrate_Num]-(unsigned int) Freq_T } else{Delta_Now=(unsigned int ) Freq_Temp - Calibrate_Frequence[Calibrate_Num];} if (Delta_Now&Delta_Min) { //如果当前差值比“世界记录”还小时 MODx_Winer[Calibrate_Num]=mod_x; //新Winner诞生 Ture_Freq[Calibrate_Num]=(unsigned int )Freq_T //记录校验后的准确频率 Delta_Min=Delta_N}}}} //取代前“世界记录”160 1、点亮红灯 Calibrate_Start();2、测量128个“纯 净”DCO频率3、找出最接近的 16个“纯净”频率 Find_RSELx_DC Ox_Winer();Measure_Temp();6、写入Flash Write_InfoFlashB( )5、合成校验数组 Calculate_InfoFlas h_Data()4、找出最优 MODx Measure_MODx()7、点亮绿灯 Calibrate_Finish();循环输出DCO DCOTest()流水账作业161 数据合成函数Calculate_InfoFlash_Data()/****************************************************************************************************** * 名 称:Calculate_InfoFlash_Data() * 功 能:基于已校验成功的RSELx、DCOx和MODx封装待写入Flash的数据 * 说 明:16位数据的格式完全仿照出厂校验参数,最高4位固定1000,然后依次为RSLEx、 DCOx和MODx。 ******************************************************************************************************/ void Calculate_InfoFlash_Data() //步骤5:将最合适的频率设定参数组合成校验数组 { unsigned char RSELx=0; unsigned char DCOx=0; unsigned char i=0; for(i=0;i&CAL_NUM;i++) { RSELx=RSELx_DCOx_Winer[i]/8; DCOx=RSELx_DCOx_Winer[i]%8; //-----出厂校准参数的16位格式为“1000_RSELx_DCOx_MODx&----InfoFlash_Data[i]=0x8000+(RSELx&&8)+(DCOx&&5)+MODx_Winer[i]; } 162 } 1、点亮红灯 Calibrate_Start();2、测量128个“纯 净”DCO频率3、找出最接近的 16个“纯净”频率 Find_RSELx_DC Ox_Winer();Measure_Temp();6、写入Flash Write_InfoFlashB( )5、合成校验数组 Calculate_InfoFlas h_Data()4、找出最优 MODx Measure_MODx()7、点亮绿灯 Calibrate_Finish();循环输出DCO DCOTest()流水账作业163 写Flash函数Write_InfoFlashB()#include &Flash.h& /****************************************************************************************************** * 名 称:Write_InfoFlashB() * 功 能:将打包好的InfoFlash_Data[]数组,依次写入InfoFlashB段 * 说 明:确保所有CCS工程的Erase Options改为选择“Erase main memory only”,只有这 样存在InfoFlashB的校验参数才不会因为烧录程序而丢失。 ******************************************************************************************************/ void Write_InfoFlashB() { //步骤6:将校验数组写入InfoFlahB段 unsigned char i=0; //-----写Flash前DCO时钟一定要重新确认一遍----BCSCTL1 = CALBC1_1MHZ; /* Set DCO to 1MHz */ DCOCTL = CALDCO_1MHZ; Flash_Init(3,'B'); //初始化Flash Flash_Erase(); //擦除Info_B //-----把InfoFlash_Data[CAL_NUM]存入InfoFlashB----for(i=0;i&CAL_NUM;i++) Flash_Direct_WriteWord(i*2,InfoFlash_Data[i]); //不擦直接写 } 164 1、点亮红灯 Calibrate_Start();2、测量128个“纯 净”DCO频率3、找出最接近的 16个“纯净”频率 Find_RSELx_DC Ox_Winer();Measure_Temp();6、写入Flash Write_InfoFlashB( )5、合成校验数组 Calculate_InfoFlas h_Data()4、找出最优 MODx Measure_MODx()7、点亮绿灯 Calibrate_Finish();循环输出DCO DCOTest()流水账作业165 完成指示函数Calibrate_Finish()/****************************************************************************************************** * 名 称:Calibrate_Finish() * 功 能:绿色LED点亮表示DCO校验完成 * 说 明:在程序运行中,一个恰当的LED指示往往能温暖人心 ******************************************************************************************************/ void Calibrate_Finish() //步骤7:绿灯亮,表示完成校验DCO { P1OUT |= BIT6; //绿灯亮红灯灭表示结束校验 P1OUT &=~BIT0; }166 1、点亮红灯 Calibrate_Start();2、测量128个“纯 净”DCO频率3、找出最接近的 16个“纯净”频率 Find_RSELx_DC Ox_Winer();Measure_Temp();6、写入Flash Write_InfoFlashB( )5、合成校验数组 Calculate_InfoFlas h_Data()4、找出最优 MODx Measure_MODx()7、点亮绿灯 Calibrate_Finish();循环输出DCO DCOTest()流水账作业167 测试函数DCOTest()? 这是一个附加的程序功能,目的是校验完成后,隔3秒循环读取InfoFlash B,设定各个频率的DCO,输出到P1.4引脚(SMCLK输出引脚)。/****************************************************************************************************** * 名 称:DCOTest() * 功 能:间隔3秒循环读取InfoFlashB中的校验参数,并据此设定DCO频率 * 说 明:可以用示波器和频率计接在P1.4(SMCLK输出口),实测DCO校验参数的准确性 ******************************************************************************************************/ void DCOTest() //步骤8:循环输出DCO各个校验频率值,供观测 { unsigned char i=1,freqCnt=1; WDTCTL=WDT_ADLY_1000; //WDT中断设为1s一次168 while(1) { if(i++ &2) {//相当于是主循环了,重复切换DCO并输出 //WTD中断唤醒三次(即定时3s),切换一次频率i=1; if(freqCnt&CAL_NUM) //范围控制(1~CAL_NUM) freqCnt=1; //-----仿照出厂校验参数CALDCO_xMHz和CALBC1_xMHz的形式设置DCO频率----DCOCTL=CALDCO_MHz(freqCnt); BCSCTL1=CALBC1_MHz(freqCnt); freqCnt++; } _bis_SR_register(LPM0_bits); //等待1s的WDT中断唤醒 } }169 练习4.1:为自己的G2单片机建立DCO校验? 自定义需要校验的DCO频率参数,数目,频率按个人喜好。? 将校验参数写入infoB中,并测试一遍是否准确。 ? 把以前写的工程中,配置DCO频率的代码,换成用自己的校验参数的代 码。 ? 以后都可以用自己的校验参数来使用G2!!170 第5讲 电容触摸按键青岛大学-美国德州仪器MSP430单片机共建实验室傅强171 5.1 电容触摸原理寄生电容 人体靠近 测量电容? 只要绝缘,电容就无处不在。 ? 人体靠近导体,就会增加导体对地电容。? 电容触摸实际就是测量电容的变化。172 5.2 电容测量原理电容测量RC充电RC振荡测量充电 时间需外部元 件测量振荡 频率G2全部IO 集成振荡173 5.3 G2系列单片机的IO振荡功能施密特反相 器数据选择器 充放电振荡频率由 内部进入TA174 电容值与振荡频率的关系175 5.4 Timer_A测频原理振荡CLK入TAWDT定时中断读取TARTAR清零176 5.5 电容触摸库函数? 将电容触摸转变为可像普通IO的输入状态寄存器PxIN那样进行读取。? 设计全局变量TouchIN,等同于IO输入状态寄存器PxIN。TouchIN.cTouchIN_Dect()TouchIN.h在WDT中断内调用Key_Measure_Freq()Key_FIFO()Key_Judge()177 变量与宏定义TouchIN.cTouchIN_Dect()TouchIN.h在WDT中断内调用Key_Measure_Freq()Key_FIFO()Key_Judge()178 变量与宏定义/*=======================TouchIn.c======================== * (1)将TouchIN_Dect()函数放置于定时中断中,就可以将触摸按键变成普通IO按键使用。 * (2)全局变量TouchIN的作用相当于PxIN寄存器。 * (3)触摸按键的识别最终转变为对无中断功能的IO按键识别上来。 *======================================================*/ #include &MSP430G2553.h& #define KEY_NUM 2 /*触摸按键数目,根据需要修改*/ //=============具体触摸按键IO宏定义,根据需要添加代码=============== #define KEY0_INIT P2DIR &= ~BIT0; P2SEL &= ~ BIT0; P2SEL2 |= BIT0 /*按键1开启振荡*/ #define KEY1_INIT P2DIR &= ~BIT5; P2SEL &= ~ BIT5; P2SEL2 |= BIT5 /*按键2开启振荡*/ #define ALL_OSC_OFF P2SEL2 &= ~(BIT0 + BIT5) /*关闭全部触摸振荡*/ /*门限频率的取值取决于定时扫描的时长,3300对应的是1.9ms定时情况,实际定时可取 1ms~20ms*/ const unsigned int FREQ_THRESHOLD[KEY_NUM]={}; /*参考值,需用仿真器查看后调整*/179 变量与宏定义变量局部变量全局变量静态局部变量共享内存独占内存独占内存出函数时值不改变仅用于函数内跨文件才使用跨函数使用仅用于函数内//-----静态局部变量---static unsigned int Freq[KEY_NUM]={0}; //当前测频值 static unsigned char Key_Buff[KEY_NUM][4]={0}; // 软件FIFO static unsigned char Key_Num=0; //按键编号 //-----全局变量,复杂程序中可以移植到Global.h统一管理----unsigned char TouchIN=0; //相当于PxIN寄存器作用,支持8个触摸按键 //unsigned int TouchIN=0; //改为此句代码可支持16个触摸按键180 库函数头文件TouchIN.cTouchIN_Dect()TouchIN.h在WDT中断内调用Key_Measure_Freq()Key_FIFO()Key_Judge()181 库函数头文件1. h头文件中,仅声明真正需要对外引用的函数和全局变量,其他函数都 被屏蔽在c文件中不可见。 2. 当我们阅读大型程序时,第一件事不是看c文件,而是看h文件。 3. 在h文件中,我们立刻能聚焦最重要的那些函数和变量,然后我们再去 c文件中查看它们是什么。 4. 如果没有h文件,我们将在“垃圾”函数的海洋中,需找“宝贝”函数。/***** TouchIN.h******/ #ifndef TOUCHIN_H_ #define TOUCHIN_H_ extern void TouchIN_Dect() ; //WDT中断事件 extern unsigned char TouchIN; // 相当于PxIN寄存器作用,支持8个触摸按键 //extern unsigned int TouchIN; // 改为此句代码可支持16个触摸按键 #endif /* TOUCHIN_H_ */182 触摸检测函数TouchIN_Dect( )TouchIN.cTouchIN_Dect()TouchIN.h在WDT中断内调用Key_Measure_Freq()Key_FIFO()Key_Judge()183 触摸检测函数TouchIN_Dect( )? 使用函数将电容触摸子函数封装起来,便于外部文件调用。/******************************************************************************************************* 名 称:TouchIN_Dect() * 功 能:触摸按键检测。 * 入口参数:无 * 出口参数:无 * 说 明:在定时中断内调用该函数。调用该函数后,全局变量TouchIN就相当于PxIN了。 * 此函数需在Touch.h中做外部函数声明。 *****************************************************************************************************/ void TouchIN_Dect() //触摸输入检测 { Key_Measure_Freq(); //测频 Key_FIFO(); //软件FIFO缓存最近4次测量数据 Key_Judge(); //仲裁按键是否按下或松开 }184 变量与宏定义TouchIN.cTouchIN_Dect()TouchIN.h在WDT中断内调用Key_Measure_Freq()Key_FIFO()Key_Judge()185 Key_Measure_Freq()* 名 称:Key_Measure_Freq() * 功 能:测量振荡频率 * 说 明:测量原理是直接对TA0主定时器读数。如需使用TA1定时器,需修改代码 *****************************************************************************************************/ void Key_Measure_Freq() { Freq[Key_Num]=TAR; //当前编号按键的频率被测得 ALL_OSC_OFF; //关闭所有振荡IO Key_Num++; //切换下一振荡IO if (Key_Num&=KEY_NUM) Key_Num=0; //各触摸按键循环交替 switch (Key_Num) { case 0 : KEY0_INIT; //振荡IO初始化 case 1 : KEY1_INIT; default: } TA0CTL = TASSEL_3+MC_2+TACLR; //连续计数清0,并开始计数 } 186 FIFO函数Key_FIFO()TouchIN.cTouchIN_Dect()TouchIN.h在WDT中断内调用Key_Measure_Freq()Key_FIFO()Key_Judge()187 FIFO函数Key_FIFO()? 测得振荡频率后,并不能直接判断手指是否接触按键,因为会有各种干 扰。本程序抗干扰的方法是用最近4次的测量结果来判断。? 总是记录最近4次结果,这属于“先进先出”FIFO(First Input First Output)RAM的存储思想。* 名 称:Key_FIFO() * 功 能:将当前所测频率与门限电平比较的结果,缓存入4B的软件FIFO * 说 明:软件FIFO的作用是保存最近4次的测量判断结果。 *****************************************************************************************************/ void Key_FIFO() //存储连续4次测量数据 { Key_Buff[Key_Num][0]=Key_Buff[Key_Num][1]; Key_Buff[Key_Num][1]=Key_Buff[Key_Num][2]; Key_Buff[Key_Num][2]=Key_Buff[Key_Num][3]; if( Freq[Key_Num]&FREQ_THRESHOLD[Key_Num]) //判断是否识别为按键 Key_Buff[Key_Num][3]=1; else Key_Buff[Key_Num][3]=0; }188 按键仲裁函数Key_Judge()TouchIN.cTouchIN_Dect()TouchIN.h在WDT中断内调用Key_Measure_Freq()Key_FIFO()Key_Judge()189 按键仲裁函数Key_Judge()? 连续4次符合门限要求,则判断为手指接触触摸键,连续4次都不符合门 限,则判断为手指离开触摸按键。结果写入全局变量TouchIN。* 名 称:Key_Judge() * 功 能:按键抗干扰。 * 说 明:连续4次都识别到按键才算按键被按下。连续4次都识别不到按键才算按键被松开。 *****************************************************************************************************/ void Key_Judge() //按键仲裁,只有连续4次测量结果一致,才算数 { if( (Key_Buff[Key_Num][0]==0)&&(Key_Buff[Key_Num][1]==0) &&(Key_Buff[Key_Num][2]==0)&&(Key_Buff[Key_Num][3]==0) ) // TouchIN=0&&Key_N //按键松开(错误代码) TouchIN &=~(1&&Key_Num); //按键松开(正确代码) if( (Key_Buff[Key_Num][0]==1)&&(Key_Buff[Key_Num][1]==1) &&(Key_Buff[Key_Num][2]==1)&&(Key_Buff[Key_Num][3]==1) ) // TouchIN =1&&Key_N //按键按下(错误代码) TouchIN |=1&&Key_N //按键按下 } 190 5.6 电容触摸举例? 如图所示MSP-EXP430G2板上P1.0上接了一个LED? 在本书配套的LaunchPad扩展板上,将MSP430G2553的P2.0和P2.5引 出作为电容触摸按键。 ? 要求按下P2.0后LED亮,按下P2.5后LED灭,程序运行过程中不阻塞 CPU,并且实现低功耗运行。191 中断子函数 WDT_ISR()void main()事件处理函数WDT_Ontime()外部库函数 TouchIN_Dect()全局变量 TouchIN192 #include &MSP430G2553.h& #include &TouchIN.h& /*触摸按键检测库函数*/ void WDT_Ontime(void); //-----对硬件相关代码进行宏定义处理----#define LED_ON P1OUT |= BIT0 /*宏定义LED所在IO*/ #define LED_OFF P1OUT &= ~BIT0 /*宏定义LED所在IO*/ void main(void) { WDTCTL = WDTPW+WDTHOLD; //关狗 //-----初始化GPIO----P1DIR |= BIT0; //LED所连IO口P1.0设为输出 P1OUT &= ~BIT0; //-----初始化WDT定时中断为16ms----WDTCTL = WDT_ADLY_16; // “超级”宏定义 IE1 |= WDTIE; //使能WDT中断 _enable_interrupts(); // 等同_EINT,使能总中断 _bis_SR_register(LPM3_bits); //等同LPM3 //while(1); }193 中断子函数 WDT_ISR()void main()事件处理函数WDT_Ontime()外部库函数 TouchIN_Dect()全局变量 TouchIN194 事件相关函数/****************************************************************************************************** * 名 称:WDT_ISR() * 功 能:响应WDT定时中断服务 ******************************************************************************************************/ #pragma vector=WDT_VECTOR / Watch dog Timer interrupt service routine __interrupt void WDT_ISR(void) { WDT_Ontime(); } /****************************************************************************************************** * 名 称:WDT_Ontime() * 功 能:WDT定时中断事件处理函数,即当WDT定时中断发生后后,下一步干什么 ******************************************************************************************************/ void WDT_Ontime(void) { TouchIN_Dect(); //-----首先必须定时扫描触摸按键检测函数----if(TouchIN & BIT0) LED_ON ; if(TouchIN & BIT1) LED_OFF; 195 } 练习5.1:电容触摸长短键? 前面我们举过一个例子,用状态机实现了机械按键长短键识别,电容触 摸按键也可以类似的实现长短按键的识别。? 要求电容触摸短按键(松手)切换LED1状态,长按键(按下)切换 LED2状态。196 状态机一致? 实现功能是一致的,当然它们的状态转换图也一样197 长短按键状态机程序中断服务子函数WDT_ISR()主函数void mian()休眠LPM3状态机函数Key_SM()按键按下事件前高后低 TouchIN前0后1长按键事件处理函数P13_OnLongClick() P20_Touch_OnLongClick()短按键事件处理函数P13_OnShortRelease() P20_Touch_OnShortRelease()按键松开事件前低后高 TouchIN前1后0长按键检测函数LongClick_Dect()IO初始化函数GPIO_Init()WDT初始化函数WDT_init()198 Key_SM()的修改/****************************************************************************************************** 机械按键SM()与触摸按键SM()主要区别 ******************************************************************************************************/ //-----查询IO的输入寄存器----// if(P1IN&BIT3) Key_Now=1; if(TouchIN&BIT0) Key_Now=1; //由P1.3改为TouchIN.0 //----- 触摸识别前0后1,表明按下----// if((Key_Past==1)&&(Key_Now==0)) if((Key_Past==0)&&(Key_Now==1)) //与机械按键的逻辑相反 Key_Dect=1; //----- 触摸识别前1后0,表明松开----if((Key_Past==1)&&(Key_Now==0)) //与机械按键的逻辑相反 Key_Dect=2 ; // P13_OnShortRelease(); //短按事件处理函数 P20_Touch_OnShortRelease(); //改为P2.0触摸短按事件处理函数 // P13_OnLongClick(); //长按事件处理函数 P20_Touch_OnLongClick(); //改为P2.0触摸长按事件处理函数199 WDT_ISR()的修改? P1IN天生存在? TouchIN需要在WDT中断中定时调用TouchIN_Dect();/***************************************************************************************************** * 名 称:WDT_ISR() * 功 能:响应WDT定时中断服务 * 说 明:不能直接判断事件,需启用状态机 ******************************************************************************************************/ #pragma vector=WDT_VECTOR __interrupt void WDT_ISR(void) { //-----触摸按键状态检测程序必须定时调用--TouchIN_Dect(); //----启用按键状态机---Key_SM(); }200 第6讲 段式液晶与IO扩展青岛大学-美国德州仪器MSP430单片机共建实验室傅强201 6.1 LCD原理? 如图所示的液晶段码图中,凡是黑色阴影部分都被灌上了传说中的液晶 ,液晶块上如果加电压(通过透明金属镀膜)就会变得“不透光”,表 现为黑色。? 如果把“共同进退”的黑块用透明导线并联,使用同一个电压信号控制 ,就称为1段。202 6.2 LCD驱动LCD显示内容丰富 电压驱动省电LED数码管简单的8字数码管电流驱 动费电 最多加个三极管放大电流可直接使用203一定频率的交流电驱动专用驱动芯片 6.3 LCD的段? 128段液晶共有32个SEGx和4个COM。? 任何一段要显示需要1个COMx和1个SEGx构成回路通电。 ? 比如我想显示“Min”段,对应的就是COM1和SEG1通电,想显示“-” 段对应的就是COM2和SEG1通电。204 段码宏定义? 首先要对128段进行宏定义,否则在编程中,神仙也记不住段号#ifndef LCD_128_H_ #define LCD_128_H_ //段码序号宏定义 #define #define #define #define ......//太长了,不写了_LCD_MIN _LCD_NEG _LCD_POS _LCD_MAX0 1 2 3205 名称 _LCD_MIN _LCD_NEG _LCD_POS _LCD_MAX _LCD_DOT0 _LCD_DOT1 _LCD_DOT2 _LCD_DOT3 _LCD_DOT4 _LCD_DOT5 _LCD_DOT6 _LCD_COLON0 _LCD_COLON1 _LCD_COLON2 _LCD_BUSY _LCD_ERROR _LCD_AUTO _LCD_RUN _LCD_PAUSE _LCD_STOP _LCD_kPA _LCD_k_g _LCD_pre_s _LCD_m_pre_s _LCD_c_m_pre_s _LCD_g _LCD_TI_logo _LCD_AC _LCD_DC _LCD_Hz _LCD_L _LCD_M3段号 0 1 2 3 8 16 24 52 60 107 123 99 83 115 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45名称 _LCD_M_Hz _LCD_k_Hz _LCD_PRECENT _LCD_k_W _LCD_m_V _LCD_m_A _LCD_k_OHOM _LCD_W _LCD_V _LCD_A _LCD_OHOM _LCD_DEGREE _LCD_dB _LCD_QDU_logo _LCD_3_AT _LCD_2_AT _LCD_AT _LCD_BELL _LCD_AM _LCD_FM _LCD_RX _LCD_LOCK _LCD_PM _LCD_CH _LCD_TX _LCD_LOWBAT _LCD_1A _LCD_1B _LCD_1C _LCD_1D _LCD_1E _LCD_1F段号 46 47 68 72 73 74 75 76 77 78 79 80 81 82 84 85 86 87 88 89 90 91 92 93 94 95 11 10 9 4 5 7名称 _LCD_1G _LCD_2A _LCD_2B _LCD_2C _LCD_2D _LCD_2E _LCD_2F _LCD_2G _LCD_3A _LCD_3B _LCD_3C _LCD_3D _LCD_3E _LCD_3F _LCD_3G _LCD_4A _LCD_4B _LCD_4C _LCD_4D _LCD_4E _LCD_4F _LCD_4G _LCD_5A _LCD_5B _LCD_5C _LCD_5D _LCD_5E _LCD_5F _LCD_5G _LCD_6A _LCD_6B _LCD_6C段号 6 19 18 17 12 13 15 14 27 26 25 20 21 23 22 55 54 53 48 49 51 50 63 62 61 56 57 59 58 71 70 69名称 _LCD_6D _LCD_6E _LCD_6F _LCD_6G _LCD_7A _LCD_7B _LCD_7C _LCD_7D _LCD_7E _LCD_7F _LCD_7G _LCD_8A _LCD_8B _LCD_8C _LCD_8D _LCD_8E _LCD_8F _LCD_8G _LCD_9A _LCD_9B _LCD_9C _LCD_9D _LCD_9E _LCD_9F _LCD_9G _LCD_10A _LCD_10B _LCD_10C _LCD_10D _LCD_10E _LCD_10F _LCD_10G段号 64 65 67 66 96 97 98 103 102 100 101 104 105 106 111 110 108 109 112 113 114 119 118 116 117 120 121 122 127 126 206 124 125 6.4 显存隔离思想? 把任何显示任务分为顶层函数和底层函数,依靠显示缓存“隔离”。? 顶层函数的任务就是决定我想显示什么,至于底层硬件实现显示,那和 我没半毛钱关系。显存共128位分为8字每字16位207 简单的显示控制函数? 直接显示某段函数LCD_DisplaySeg():在对单位符号等段进行显示的时 候,直接调用段宏定义将会非常方便。? 直接消隐某段函数LCD_ClearSeg():在更新显示时,不要忘记消隐。 ? 清除全屏显示函数LCD_Clear():当屏幕显示内容很多,需要一次性清屏 时,调用该函数。/****************************************************************************************************** * 名 称:LCD_DisplaySeg() * 功 能:显示一段段码 * 入口参数:SegNum:0~127段号码 * 范 例:LCD_DisplaySeg(_LCD_TI_logo),显示TI logo **************************************************************************************************** */ void LCD_DisplaySeg(unsigned char SegNum) { LCD_Buffer[SegNum/16] |= 1&&(SegNum%16); }208 简单的显示控制函数****************************************************************************************************** * 名 称:LCD_ClearSeg() * 功 能:清除一段段码 * 入口参数:SegNum:0~127段号码 * 范 例:LCD_ClearSeg(_LCD_TI_logo),显示TI logo **************************************************************************************************** */ void LCD_ClearSeg(unsigned char SegNum) { LCD_Buffer[SegNum/16] &= ~(1&&(SegNum%16)); } /****************************************************************************************************** * 名 称:LCD_Clear() * 功 能:清屏 **************************************************************************************************** */ void LCD_Clear() { unsigned char i=0; for ( i=0;i&=7;i++) LCD_Buffer[i]=0; }209 6.5 显示译码? 可以算出128位显示缓存从高 位至低位依次为0x17F7 _ B7D7 _ 0000 _ 00AF _ AD6C _ 0100 _ 0E5C _7600210 显示缓存LCD_ Buffer[7]范围高4位 1●127-112次高4位 7 ● ● 123 1227●●次低4位 F ● ● 118D●低4位 7 ● ● 115 1147●127126B125124121120119117116113112LCD_ Buffer[6]LCD_ Buffer[5] LCD_ Buffer[4] LCD_ Buffer[3] LCD_ Buffer[2] LCD_ Buffer[1] LCD_ Buffer[0]111-96● 111 110 0● 109● 108 017● 106 0● 105● 104● 103● 102 0 101● 100 99● 98 0● 97● 9695-80 95 79-64 79 63-48 ● 63 47-32 47 31-16 31 15-0 15 30 29 28 ● 12 46 0 ● 27 ● 26 45 44 43 42 E ● 25 24 23 ● 22 21 41 62 0 78 A ● 61 60 ● 59 ● 58 1 57 77 76 75 74 D ● 56 55 ● 54 0 73 72 94 0 93 92 91 90 0 ● 71 70 6 ● 53 52 ● 51 ● 50 0 37 5 ● 20 ● 19 ● 18 17 16 36 35 34 C 33 32 49 48 89 88 87 86 A ● 69 68 ● 67 ● 66 C 85 84 83 82 F ● 65 ●

我要回帖

更多关于 键盘加减音量 的文章

 

随机推荐