<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_给我一杯酒</title><subtitle type="text"/><id>http://feed.cnblogs.com/blog/u/76625/rss</id><updated>2012-02-23T08:31:52Z</updated><author><name>给我一杯酒</name><uri>http://www.cnblogs.com/Engin/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Engin/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/76625/rss"/><entry><id>http://www.cnblogs.com/Engin/archive/2011/10/01/2197746.html</id><title type="text">MSP430程序库&amp;lt;十六&amp;gt;总结</title><summary type="text">全国电子设计竞赛结束已经有一段时间了，这个程序库也就到这儿了，程序库已经包含msp430f14x msp430f16x系列的单片机大多数的片内资源。目录如下： MSP430程序库&lt;一&gt;...</summary><published>2011-10-01T11:21:00Z</published><updated>2011-10-01T11:21:00Z</updated><author><name>给我一杯酒</name><uri>http://www.cnblogs.com/Engin/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Engin/archive/2011/10/01/2197746.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Engin/archive/2011/10/01/2197746.html"/><content type="html">&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;全国电子设计竞赛结束已经有一段时间了，这个程序库也就到这儿了，程序库已经包含msp430f14x msp430f16x系列的单片机大多数的片内资源。目录如下：&lt;/p&gt;&lt;/blockquote&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/06/28/2092572.html" target="_blank"&gt;MSP430程序库&amp;lt;一&amp;gt;综述&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/07/06/2098990.html" target="_blank"&gt;MSP430程序库&amp;lt;二&amp;gt;UART异步串口&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/07/08/2100932.html" target="_blank"&gt;MSP430程序库&amp;lt;三&amp;gt;12864液晶程序库&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/07/31/2122822.html" target="_blank"&gt;MSP430程序库&amp;lt;四&amp;gt;printf和scanf函数移植&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/09/2133036.html" target="_blank"&gt;MSP430程序库&amp;lt;五&amp;gt;SPI同步串行通信&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/20/2147022.html" target="_blank"&gt;MSP430程序库&amp;lt;六&amp;gt;通过SPI操作AD7708&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/21/2147724.html" target="_blank"&gt;MSP430程序库&amp;lt;七&amp;gt;按键&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/22/2149448.html" target="_blank"&gt;MSP430程序库&amp;lt;八&amp;gt;DAC12的使用&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/23/2151130.html" target="_blank"&gt;MSP430程序库&amp;lt;九&amp;gt;数码管显示&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/26/2154677.html" target="_blank"&gt;MSP430程序库&amp;lt;十&amp;gt;ADC12模块&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/27/2155680.html" target="_blank"&gt;MSP430程序库&amp;lt;十一&amp;gt;定时器TA的PWM输出&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/28/2156007.html" target="_blank"&gt;MSP430程序库&amp;lt;十二&amp;gt;SVS(电源电压监控器)模块&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/28/2156346.html" target="_blank"&gt;MSP430程序库&amp;lt;十三&amp;gt;硬件乘法器使用&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/29/2158284.html" target="_blank"&gt;MSP430程序库&amp;lt;十四&amp;gt;DMA程序库&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/31/2160534.html" target="_blank"&gt;MSP430程序库&amp;lt;十五&amp;gt;Flash控制器&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/10/01/2197746.html" target="_blank"&gt;MSP430程序库&amp;lt;十六&amp;gt;总结&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;这个程序库的程序和有关资料可以用svn check-out 地址为：&lt;a href="svn://www.oksvn.com/msp430" target="_blank"&gt;svn://www.oksvn.com/msp430&lt;/a&gt;，这里；也可以从&lt;a href="http://files.cnblogs.com/Engin/%E7%A8%8B%E5%BA%8F%E5%BA%93.rar" target="_blank"&gt;程序库&lt;/a&gt;下载。完整（包含所有使用资料的版本）版本可以到&lt;a href="http://dl.dbank.com/c04y2bbx4a" target="_blank"&gt;http://dl.dbank.com/c04y2bbx4a&lt;/a&gt;下载。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;程序库的内容就到这里了，多谢广大网友的支持啦；有什么不足之处，欢迎拍砖。&lt;/p&gt;&lt;p&gt;作者：&lt;strong&gt;&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;给我一杯酒&lt;/a&gt;&lt;/strong&gt; &lt;br /&gt;出处：&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;http://Engin.cnblogs.com/&lt;/a&gt; &lt;br /&gt;本文版权归作者和博客园共有，欢迎转载，转载保留此段文字并且注明出处；谢谢。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/Engin/aggbug/2197746.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/10/01/2197746.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Engin/archive/2011/08/31/2160534.html</id><title type="text">MSP430程序库&amp;lt;十五&amp;gt;Flash控制器</title><summary type="text">一般，在单片机中的Flash存储器用于存放程序代码，属于只读型存储器。而在MSP430些列的单片机中，都可以通过内置的Flash控制器擦除或改写任何一段的内容。另外，msp430的单片机内部还专...</summary><published>2011-08-31T03:42:00Z</published><updated>2011-08-31T03:42:00Z</updated><author><name>给我一杯酒</name><uri>http://www.cnblogs.com/Engin/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Engin/archive/2011/08/31/2160534.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Engin/archive/2011/08/31/2160534.html"/><content type="html">&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;一般，在单片机中的Flash存储器用于存放程序代码，属于只读型存储器。而在MSP430些列的单片机中，都可以通过内置的Flash控制器擦除或改写任何一段的内容。另外，msp430的单片机内部还专门留有一段Flash区域(information memory)，用于存放掉电后需要永久保存的数据。利用430内部的Flash控制器，可以完成较大容量的数据记录、用户设置参数在掉电后的保存等功能。&lt;/p&gt; &lt;/blockquote&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;硬件介绍：&lt;/strong&gt;       &lt;p&gt;要对Flash读写，首先要了解MSP430的存储器组织。430单片机的存储器组织结构采用冯诺依曼结构，RAM和ROM统一编址在同一寻址空间中，没有代码空间和数据空间之分。&lt;/p&gt;      &lt;p&gt;一般430的单片机都统一编址在0-64k地址范围中，只有少数高端的型号才能突破64k（如：FG461x系列）。绝大多数的msp430单片机都编址在64kB范围内。地址的大概编码方式如下：&lt;/p&gt;      &lt;p&gt;&lt;a href="file:///C:/Documents%20and%20Settings/Administrator/Local%20Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image4.png"&gt;&lt;img title="image_thumb1" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="271" alt="image_thumb1" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/20110831113839769.png" width="521" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;      &lt;p&gt;这是msp430f425的存储器分配图，其他在64k范围内的存储器的单片机编址方式与此类似：低256B是寄存器区，然后是RAM；空白；1000H到10FFH是信息Flash区；大于1100H-0FFFFH是主存储器区(从0FFFFH开始往低地址有单片机的主Flash，多余的部分空白)。&lt;/p&gt;      &lt;p&gt;MSP430F14x的Flash分布：&lt;/p&gt;      &lt;p&gt;&amp;#160;&lt;a href="file:///C:/Documents%20and%20Settings/Administrator/Local%20Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image5%5B1%5D.png"&gt;&lt;img title="image_thumb21[1]" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="183" alt="image_thumb21[1]" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108311138444395.png" width="561" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;      &lt;p&gt;MSP430F16x的Flash分布：&lt;/p&gt;      &lt;p&gt;&amp;#160;&lt;a href="file:///C:/Documents%20and%20Settings/Administrator/Local%20Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image6%5B1%5D.png"&gt;&lt;img title="image_thumb41[1]" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="175" alt="image_thumb41[1]" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108311138479709.png" width="573" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;      &lt;p&gt;主Flash部分和信息Flash部分如下(60kB Flash对应的单片机，如msp430f149、msp430f149)：&lt;/p&gt;      &lt;p&gt;&lt;/p&gt;      &lt;p&gt;&lt;/p&gt;      &lt;p&gt;&lt;/p&gt;      &lt;p&gt;&lt;a href="file:///C:/Documents%20and%20Settings/Administrator/Local%20Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image9.png"&gt;&lt;img title="image_thumb4" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="375" alt="image_thumb4" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108311139402191.png" width="265" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;      &lt;p&gt;主Flash分为以512B为段的单位，0段是单片机中断向量等程序入口地址，使用时不要擦除此段或改写此段，若要擦除或是改写，请先保存内容到RAM或其他段；主Flash各段内容均要避免写入或擦除，以免造成不可预料的后果。&lt;/p&gt;      &lt;p&gt;信息Flash分为两段：段A和段B，每段128B；可以保存用户自己的内容(主Flash也可以但是要避免与程序代码区冲突)；这里就把信息Flash的两段称为InfoA(1080H-10FFh)和InfoB(1000H-10FFH)。&lt;/p&gt;      &lt;p&gt;Flash的操作包括：字或字节写入；块写入；段擦除；主Flash擦除；全部擦除。任何的Flash操作都可以从Flash或从RAM中运行。&lt;/p&gt;      &lt;p&gt;Flash操作时需要时序发生器，Flash控制器内部含有时序发生器用以产生所需的Flash时钟，Flash时钟的范围必须在257kHz到476kHz之间。时序发生器的框图如下：&lt;/p&gt;      &lt;p&gt;&lt;a href="file:///C:/Documents%20and%20Settings/Administrator/Local%20Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image51.png"&gt;&lt;img title="image_thumb2" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="152" alt="image_thumb2" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108311139417373.png" width="408" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;      &lt;p&gt;时序发生器可以选择ACLK、MCLK、SMCLK作为时钟源，通过分频获得所需的257kHz到476kHz之间的Flash操作时钟。如果时钟频率不再这个范围内，将会产生不可预料的结果。&lt;/p&gt;      &lt;p&gt;擦除：擦除之后，存储器中的bit都变为1；Flash中的每一位都可以通过编程写入有1到0，但是要想由0变为1，必须通过擦除周期。擦除的最小单位是段。有三种擦除模式：&lt;/p&gt;      &lt;span style="color: green"&gt;MERAS   ERASE       Erase Mode&lt;br/&gt;0       1           Segment erase&lt;br/&gt;1       0           Mass erase (all main memory segments)&lt;br/&gt;1       1           Erase all flash memory (main and information .segments)&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;可以通过&lt;span style="color: green"&gt;MERAS、ERASE &lt;font color="#000000"&gt;位来设置擦除的模式：段擦除，主Flash擦除，全部擦除。&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;    &lt;p&gt;&lt;span style="color: green"&gt;&lt;font color="#000000"&gt;对要擦除段内的一个地址空写入启动擦出周期：空写入可以启动时序发生器和擦除操作。空写入后BUSY位立即变高直到擦除周期结束，这一位变为低(0)。&lt;/font&gt;&lt;/span&gt;BUSY, MERAS和 ERASE位在擦除周期结束后会自动复位。擦除周期的时间和要擦出的Flash大小无关，每次擦除的时间对于MSP430F1xx系系列单片机来说，所需时间是一样的。擦除的时序如下：&lt;/p&gt;    &lt;p&gt;&lt;a href="file:///C:/Documents%20and%20Settings/Administrator/Local%20Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image91.png"&gt;&lt;img title="image_thumb41" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="164" alt="image_thumb41" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/2011083111394313.png" width="451" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;当空写入到的地址不在要擦除的段地址范围内的时候，空写入无效，直接被忽略。在擦除周期内，应该关中断，直到擦除完成，重新开中断，擦除期间的中断已经置标志位，开中断后立即响应。&lt;/p&gt;    &lt;p&gt;从Flash中启动的擦除操作：擦除操作可以从Flash中启动或是从RAM中启动。当操作是从Flash中启动的时候，Flash控制器控制了操作时序，CPU运行被暂停直到擦除结束。擦除周期结束后，CPU继续执行，从空写入之后的指令开始运行。当从Flash中启动擦除操作时，可以擦除即将运行的程序所在的段，如果擦除了即将运行的程序所在的Flash段时，擦除结束后，CPU的运行不可预料。&lt;/p&gt;    &lt;p&gt;从Flash启动时擦除周期如下：&lt;/p&gt;    &lt;p&gt;&lt;a href="file:///C:/Documents%20and%20Settings/Administrator/Local%20Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image5.png"&gt;&lt;img title="image_thumb2[1]" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="246" alt="image_thumb2[1]" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108311139576549.png" width="263" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;p&gt;用户指南里面的示例汇编程序如下：&lt;/p&gt;    &lt;span style="color: green"&gt;; Segment Erase from flash. 514 kHz &amp;lt; SMCLK &amp;lt; 952 kHz&lt;br/&gt;; Assumes ACCVIE = NMIIE = OFIE = 0.&lt;br/&gt;&lt;/span&gt;MOV #WDTPW+WDTHOLD,&amp;amp;WDTCTL &lt;span style="color: green"&gt;; Disable WDT&lt;br/&gt;&lt;/span&gt;DINT &lt;span style="color: green"&gt;//; Disable interrupts&lt;br/&gt;&lt;/span&gt;MOV #FWKEY+FSSEL1+FN0,&amp;amp;FCTL2 &lt;span style="color: green"&gt;; SMCLK/2&lt;br/&gt;&lt;/span&gt;MOV #FWKEY,&amp;amp;FCTL3&lt;span style="color: green"&gt; ; Clear LOCK&lt;br/&gt;&lt;/span&gt;MOV #FWKEY+ERASE,&amp;amp;FCTL1 &lt;span style="color: green"&gt;; Enable segment erase&lt;br/&gt;&lt;/span&gt;CLR &amp;amp;0FC10h &lt;span style="color: green"&gt;; Dummy write, erase S1&lt;br/&gt;&lt;/span&gt;MOV #FWKEY+LOCK,&amp;amp;FCTL3 &lt;span style="color: green"&gt;; Done, set LOCK&lt;br/&gt;&lt;/span&gt;... &lt;span style="color: green"&gt;; Re-enable WDT?&lt;br/&gt;&lt;/span&gt;EINT&lt;span style="color: green"&gt; ; Enable interrupts&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;从RAM中启动擦除操作：任意擦除周期都可以从RAM启动，这时CPU不再暂停而是继续从RAM中运行接下来的程序。CPU可以访问任何Flash地址之前，必须检查BUSY位以确定擦除周期结束。如果BUSY = 1访问Flash，这是一个访问冲突，这时ACCVIFG将被设置，而擦除的结果将是不可预测的的。&lt;/p&gt;    &lt;p&gt;从RAM中启动擦除操作时，过程如下：&lt;/p&gt;    &lt;p&gt;&lt;a href="file:///C:/Documents%20and%20Settings/Administrator/Local%20Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image10.png"&gt;&lt;img title="image_thumb5" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="303" alt="image_thumb5" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108311140225536.png" width="229" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;p&gt;要在擦除之前确认没有访问Flash，然后擦除完成之前不允许访问Flash。&lt;/p&gt;    &lt;span style="color: green"&gt;; Segment Erase from RAM. 514 kHz &amp;lt; SMCLK &amp;lt; 952 kHz&lt;br/&gt;; Assumes ACCVIE = NMIIE = OFIE = 0.&lt;br/&gt;&lt;/span&gt;MOV #WDTPW+WDTHOLD,&amp;amp;WDTCTL  &lt;span style="color: green"&gt;; Disable WDT&lt;br/&gt;&lt;/span&gt;DINT                        &lt;span style="color: green"&gt;; Disable interrupts&lt;br/&gt;&lt;/span&gt;L1 BIT #BUSY,&amp;amp;FCTL3         &lt;span style="color: green"&gt;; Test BUSY&lt;br/&gt;&lt;/span&gt;JNZ L1                      &lt;span style="color: green"&gt;; Loop while busy&lt;br/&gt;&lt;/span&gt;MOV #FWKEY+FSSEL1+FN0,&amp;amp;FCTL2&lt;span style="color: green"&gt;; SMCLK/2&lt;br/&gt;&lt;/span&gt;MOV #FWKEY,&amp;amp;FCTL3           &lt;span style="color: green"&gt;; Clear LOCK&lt;br/&gt;&lt;/span&gt;MOV #FWKEY+ERASE,&amp;amp;FCTL1     &lt;span style="color: green"&gt;; Enable erase&lt;br/&gt;&lt;/span&gt;CLR &amp;amp;0FC10h                 &lt;span style="color: green"&gt;; Dummy write, erase S1&lt;br/&gt;&lt;/span&gt;L2 BIT #BUSY,&amp;amp;FCTL3         &lt;span style="color: green"&gt;; Test BUSY&lt;br/&gt;&lt;/span&gt;JNZ L2                      &lt;span style="color: green"&gt;; Loop while busy&lt;br/&gt;&lt;/span&gt;MOV #FWKEY+LOCK,&amp;amp;FCTL3      &lt;span style="color: green"&gt;; Done, set LOCK&lt;br/&gt;&lt;/span&gt;...                         &lt;span style="color: green"&gt;; Re-enable WDT?&lt;br/&gt;&lt;/span&gt;EINT                        &lt;span style="color: green"&gt;; Enable interrupts&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;写Flash操作：写入的模式由WRT和BLKWRT位来确定：&lt;/p&gt;    &lt;span style="color: green"&gt;BLKWRT      WRT         Write Mode&lt;br/&gt;0           1           Byte/word write&lt;br/&gt;1           1           Block write&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;这两种模式中块写入大约是字或字节写操作时的两倍快，因为在块写入完成之前，变成电压一直维持直到块写入完成。同一个位置不能在擦除周期之前写入两次或以上，否则将发生数据损坏。写操作时，BUSY位被置1，写入完成后，BUSY被自动清零。如果写操作是从RAM发起的，在BUSY=1时，程序不能访问Flash，否则会发生访问冲突，置位ACCVIFG，Flash写入操作不可以预料。&lt;/p&gt;    &lt;p&gt;字或字节写入：字或字节写入可以从Flash内部发起，也可以从RAM中发起。如果是从Flash中启动的写操作，时序将由Flash控制，在写入完成之前CPU运行将被暂停。写入完成后CPU将继续运行。&lt;/p&gt;    &lt;p&gt;操作时序如下：&lt;/p&gt;    &lt;p&gt;&lt;a href="file:///C:/Documents%20and%20Settings/Administrator/Local%20Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image14.png"&gt;&lt;img title="image_thumb7" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="142" alt="image_thumb7" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108311140238176.png" width="377" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;p&gt;若是从RAM中启动写Flash，程序将继续从RAM中运行。CPU再次访问Flash之前必须确认BUSY位已经清零，否则会发生访问冲突，置位ACCVIFG，写入的结果将不可预料。&lt;/p&gt;    &lt;span style="color: green"&gt;字或字节写入模式下，内部产生的编程电压时适用于完整的64个字节块的写入&lt;br/&gt;In byte/word mode, the internally-generated programming voltage is applied&lt;br/&gt;to the complete 64-byte block, each time a byte or word is written, for 32 of the&lt;br/&gt;35 fFTG cycles. With each byte or word write, the amount of time the block is&lt;br/&gt;subjected to the programming voltage accumulates. The cumulative&lt;br/&gt;programming time, tCPT, must not be exceeded for any block. If the cumulative&lt;br/&gt;programming time is met, the block must be erased before performing any&lt;br/&gt;further writes to any address within the block.&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;从Flash发起写字节或字时：&lt;/p&gt;    &lt;p&gt;&lt;a href="file:///C:/Documents%20and%20Settings/Administrator/Local%20Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image19.png"&gt;&lt;img title="image_thumb10" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="231" alt="image_thumb10" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108311140289818.png" width="256" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;span style="color: green"&gt;; Byte/word write from flash. 514 kHz &amp;lt; SMCLK &amp;lt; 952 kHz&lt;br/&gt;; Assumes 0FF1Eh is already erased&lt;br/&gt;; Assumes ACCVIE = NMIIE = OFIE = 0.&lt;br/&gt;&lt;/span&gt;MOV #WDTPW+WDTHOLD,&amp;amp;WDTCTL      &lt;span style="color: green"&gt;; Disable WDT&lt;br/&gt;&lt;/span&gt;DINT ; Disable interrupts&lt;br/&gt;MOV #FWKEY+FSSEL1+FN0,&amp;amp;FCTL2    &lt;span style="color: green"&gt;; SMCLK/2&lt;br/&gt;&lt;/span&gt;MOV #FWKEY,&amp;amp;FCTL3               &lt;span style="color: green"&gt;; Clear LOCK&lt;br/&gt;&lt;/span&gt;MOV #FWKEY+WRT,&amp;amp;FCTL1           &lt;span style="color: green"&gt;; Enable write&lt;br/&gt;&lt;/span&gt;MOV #0123h,&amp;amp;0FF1Eh              &lt;span style="color: green"&gt;; 0123h −&amp;gt; 0FF1Eh&lt;br/&gt;&lt;/span&gt;MOV #FWKEY,&amp;amp;FCTL1               &lt;span style="color: green"&gt;; Done. Clear WRT&lt;br/&gt;&lt;/span&gt;MOV #FWKEY+LOCK,&amp;amp;FCTL3          &lt;span style="color: green"&gt;; Set LOCK&lt;br/&gt;&lt;/span&gt;...                             &lt;span style="color: green"&gt;; Re-enable WDT?&lt;br/&gt;&lt;/span&gt;EINT                            &lt;span style="color: green"&gt;; Enable interrupts&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;从RAM中启动写入操作时：&lt;/p&gt;    &lt;p&gt;&lt;a href="file:///C:/Documents%20and%20Settings/Administrator/Local%20Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image23.png"&gt;&lt;img title="image_thumb12" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="306" alt="image_thumb12" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108311140519229.png" width="224" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;span style="color: green"&gt;; Byte/word write from RAM. 514 kHz &amp;lt; SMCLK &amp;lt; 952 kHz&lt;br/&gt;; Assumes 0FF1Eh is already erased&lt;br/&gt;; Assumes ACCVIE = NMIIE = OFIE = 0.&lt;br/&gt;&lt;/span&gt;MOV #WDTPW+WDTHOLD,&amp;amp;WDTCTL      &lt;span style="color: green"&gt;; Disable WDT&lt;br/&gt;&lt;/span&gt;DINT                            &lt;span style="color: green"&gt;; Disable interrupts&lt;br/&gt;&lt;/span&gt;L1 BIT #BUSY,&amp;amp;FCTL3             &lt;span style="color: green"&gt;; Test BUSY&lt;br/&gt;&lt;/span&gt;JNZ L1                          &lt;span style="color: green"&gt;; Loop while busy&lt;br/&gt;&lt;/span&gt;MOV #FWKEY+FSSEL1+FN0,&amp;amp;FCTL2    &lt;span style="color: green"&gt;; SMCLK/2&lt;br/&gt;&lt;/span&gt;MOV #FWKEY,&amp;amp;FCTL3               &lt;span style="color: green"&gt;; Clear LOCK&lt;br/&gt;&lt;/span&gt;MOV #FWKEY+WRT,&amp;amp;FCTL1           &lt;span style="color: green"&gt;; Enable write&lt;br/&gt;&lt;/span&gt;MOV #0123h,&amp;amp;0FF1Eh              &lt;span style="color: green"&gt;; 0123h −&amp;gt; 0FF1Eh&lt;br/&gt;&lt;/span&gt;L2 BIT #BUSY,&amp;amp;FCTL3             &lt;span style="color: green"&gt;; Test BUSY&lt;br/&gt;&lt;/span&gt;JNZ L2                          &lt;span style="color: green"&gt;; Loop while busy&lt;br/&gt;&lt;/span&gt;MOV #FWKEY,&amp;amp;FCTL1               &lt;span style="color: green"&gt;; Clear WRT&lt;br/&gt;&lt;/span&gt;MOV #FWKEY+LOCK,&amp;amp;FCTL3          &lt;span style="color: green"&gt;; Set LOCK&lt;br/&gt;&lt;/span&gt;...                             &lt;span style="color: green"&gt;; Re-enable WDT?&lt;br/&gt;&lt;/span&gt;EINT                            &lt;span style="color: green"&gt;; Enable interrupts&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;块写入：当需要写入连续的多个字或字节时，块写入能够能够提高Flash访问速度。块写入时，内部产生的编程电压一直存在在64个字节的块写入期间。块写入不能有Flash存储器内启动，必须从RAM中发起块写入操作。块写入期间，BUSY位被置位。在写入每个字节或字时必须检测WAIT位。下一个字或字节能够被写入时，WAIT位被置位。&lt;/p&gt;    &lt;p&gt;&lt;a href="file:///C:/Documents%20and%20Settings/Administrator/Local%20Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image29.png"&gt;&lt;img title="image_thumb16" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="190" alt="image_thumb16" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108311140563595.png" width="358" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;p&gt;块写入的过程如下：&lt;/p&gt;    &lt;p&gt;&amp;#160;&lt;a href="file:///C:/Documents%20and%20Settings/Administrator/Local%20Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image34.png"&gt;&lt;img title="image_thumb19" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="409" alt="image_thumb19" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108311140575712.png" width="232" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;    &lt;span style="color: green"&gt;; Write one block starting at 0F000h.&lt;br/&gt;; Must be executed from RAM, Assumes Flash is already erased.&lt;br/&gt;; 514 kHz &amp;lt; SMCLK &amp;lt; 952 kHz&lt;br/&gt;; Assumes ACCVIE = NMIIE = OFIE = 0.&lt;br/&gt;&lt;/span&gt;MOV #32,R5                      &lt;span style="color: green"&gt;; Use as write counter&lt;br/&gt;&lt;/span&gt;MOV #0F000h,R6                  &lt;span style="color: green"&gt;; Write pointer&lt;br/&gt;&lt;/span&gt;MOV #WDTPW+WDTHOLD,&amp;amp;WDTCTL      &lt;span style="color: green"&gt;; Disable WDT&lt;br/&gt;&lt;/span&gt;DINT                            &lt;span style="color: green"&gt;; Disable interrupts&lt;br/&gt;&lt;/span&gt;L1 BIT #BUSY,&amp;amp;FCTL3             &lt;span style="color: green"&gt;; Test BUSY&lt;br/&gt;&lt;/span&gt;JNZ L1 ; Loop &lt;span style="color: blue"&gt;while &lt;/span&gt;busy&lt;br/&gt;MOV #FWKEY+FSSEL1+FN0,&amp;amp;FCTL2    &lt;span style="color: green"&gt;; SMCLK/2&lt;br/&gt;&lt;/span&gt;MOV #FWKEY,&amp;amp;FCTL3               &lt;span style="color: green"&gt;; Clear LOCK&lt;br/&gt;&lt;/span&gt;MOV #FWKEY+BLKWRT+WRT,&amp;amp;FCTL1    &lt;span style="color: green"&gt;; Enable block write&lt;br/&gt;&lt;/span&gt;L2 MOV Write_Value,0(R6)        &lt;span style="color: green"&gt;; Write location&lt;br/&gt;&lt;/span&gt;L3 BIT #WAIT,&amp;amp;FCTL3             &lt;span style="color: green"&gt;; Test WAIT&lt;br/&gt;&lt;/span&gt;JZ L3                           &lt;span style="color: green"&gt;; Loop while WAIT=0&lt;br/&gt;&lt;/span&gt;INCD R6                         &lt;span style="color: green"&gt;; Point to next word&lt;br/&gt;&lt;/span&gt;DEC R5                          &lt;span style="color: green"&gt;; Decrement write counter&lt;br/&gt;&lt;/span&gt;JNZ L2                          &lt;span style="color: green"&gt;; End of block?&lt;br/&gt;&lt;/span&gt;MOV #FWKEY,&amp;amp;FCTL1               &lt;span style="color: green"&gt;; Clear WRT,BLKWRT&lt;br/&gt;&lt;/span&gt;L4 BIT #BUSY,&amp;amp;FCTL3             &lt;span style="color: green"&gt;; Test BUSY&lt;br/&gt;&lt;/span&gt;JNZ L4                          &lt;span style="color: green"&gt;; Loop while busy&lt;br/&gt;&lt;/span&gt;MOV #FWKEY+LOCK,&amp;amp;FCTL3          &lt;span style="color: green"&gt;; Set LOCK&lt;br/&gt;&lt;/span&gt;...                             &lt;span style="color: green"&gt;; Re-enable WDT if needed&lt;br/&gt;&lt;/span&gt;EINT                            &lt;span style="color: green"&gt;; Enable interrupts&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;当任何写或擦除操作是从RAM启动，而BUSY = 1，CPU不能读取或写入或从任何Flash位置。否则，发生访问冲突，ACCVIFG设置，结果是不可预知的。此外，如果闪存写入让WRT= 0，ACCVIFG中断标志设置，Flash不受影响。&lt;/p&gt;    &lt;p&gt;如果写入或擦除操作时从Flash启动的，CPU访问下一条指令时(从Flash读取指令)，Flash控制器返回03FFFH给CPU；03FFFH是指令JMP PC，这让CPU一直循环直到Flash操作完成。Flash写入或擦除操作完成后，允许CPU继续访问接下来的指令。&lt;/p&gt;    &lt;p&gt;当BUSY=1时，Flash访问时：&lt;/p&gt;    &lt;p&gt;&lt;a href="file:///C:/Documents%20and%20Settings/Administrator/Local%20Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image38.png"&gt;&lt;img title="image_thumb21" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="205" alt="image_thumb21" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108311140593925.png" width="389" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;p&gt;在开始Flash操作之前，需要停止所有的中断源。如果在Flash操作期间有中断响应，读中断服务程序的地址时，将收到03FFFH作为中断服务程序的地址。如果BUSY=1；CPU将一直执行难IMP PC指令；Flash操作完成后，将从03FFFH执行中断服务程序而不是正确的中断程序的地址。&lt;/p&gt;    &lt;p&gt;停止写入或擦除：任何写入和擦除操作都可以在正常完成之前，通过设置紧急退出位EMEX退出操作。设置EMEX时，立即停止当前活动的操作，停止Flash控制器；所有的Flash操作停止，Flash返回可读模式，FCTL1的所有位复位；操作的结果不可预料。&lt;/p&gt;    &lt;p&gt;设置和访问Flash控制器：FCTLx是16位的、密码保护的、可读写的寄存器。写入这些寄存器都必须在高位包含密码0A5H，如果写入的不是0A5H，将会引起复位。读寄存器时高位读出的是96H。&lt;/p&gt;    &lt;p&gt;在擦除或写入字或字节时写FCTL1寄存器将会引起访问冲突，置位ACCVIFG.块写入时，WAIT=1时可以写FCTL1寄存器，当WAIT=0时写FCTL1寄存器是访问冲突，置位ACCVIFG。BUSY=1时，所有写入FCTL2寄存器都是访问冲突。BUSY=1时，所有的FCTLx都可以读操作，不会引起访问冲突。&lt;/p&gt;    &lt;p&gt;Flash的中断：Flash控制器有两个中断源：KEYV, 和ACCVIFG。ACCVIFG在访问冲突的时候被置位。当ACCVIE在Flash操作完成后被重新使能后ACCVIFG会引起中断请求。ACCIFG和NMI同样的中断向量，所以这个中断不需要GIE位允许即可产生中断请求。必须通过软件检测ACCVIFG位，以确定发生了访问冲突；ACCVIFG位必须软件复位。KEYV是关键值错误当写Flash的寄存器时没有写正确的高位密码时被置位，这是会立刻引起PUC信号复位整个硬件。&lt;/p&gt;    &lt;p&gt;编程Flash的硬件：编程430的Flash内容有三种选择，通过JTAG、通过BSL和用户定制。用户定制即是通过单片机的程序访问自己的Flash。&lt;/p&gt;    &lt;p&gt;&lt;a href="file:///C:/Documents%20and%20Settings/Administrator/Local%20Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image43.png"&gt;&lt;img title="image_thumb24" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="353" alt="image_thumb24" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108311141109051.png" width="483" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;p&gt;Flash的寄存器列表如下：&lt;/p&gt;    &lt;span style="color: green"&gt;Register                            Short Form      Register Type   Address     Initial State&lt;br/&gt;Flash memory control register 1     FCTL1           Read/write      0128h       09600h with PUC&lt;br/&gt;Flash memory control register 2     FCTL2           Read/write      012Ah       09642h with PUC&lt;br/&gt;Flash memory control register 3     FCTL3           Read/write      012Ch       09618h with PUC&lt;br/&gt;Interrupt Enable 1                  IE1             Read/write      000h        Reset with PUC&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;Flash的硬件部分就介绍这么多了，有什么不大懂的地方请参考TI提供的用户指南。&lt;/p&gt;  &lt;/li&gt;  &lt;li&gt;&lt;strong&gt;程序实现：&lt;/strong&gt;     &lt;p&gt;首先设置Flash的时钟，初始化Flash控制器：&lt;/p&gt;    &lt;span style="color: blue"&gt;void &lt;/span&gt;FlashInit()&lt;br/&gt;{&lt;br/&gt;    FCTL2 = FWKEY + FSSEL_2 + FN1;          &lt;span style="color: green"&gt;// 默认 SMCLK/3 =333KHz &lt;br/&gt;&lt;/span&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;这个函数仅仅设置了时钟。&lt;/p&gt;    &lt;p&gt;擦除函数：&lt;/p&gt;    &lt;span style="color: blue"&gt;void &lt;/span&gt;FlashErase(&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;Addr)  &lt;br/&gt;{ &lt;br/&gt;    &lt;span style="color: blue"&gt;char &lt;/span&gt;*FlashPtr;&lt;br/&gt;    FlashPtr = (&lt;span style="color: blue"&gt;char &lt;/span&gt;*)Addr;&lt;br/&gt;    FCTL1 = FWKEY + ERASE;                      &lt;span style="color: green"&gt;// Set Erase bit&lt;br/&gt;    &lt;/span&gt;FCTL3 = FWKEY;                              &lt;span style="color: green"&gt;// Clear Lock bit&lt;br/&gt;    &lt;/span&gt;DINT;&lt;br/&gt;    *FlashPtr = 0;                              &lt;span style="color: green"&gt;// Dummy write to erase Flash segment B&lt;br/&gt;    &lt;/span&gt;WaitForEnable();                            &lt;span style="color: green"&gt;//Busy&lt;br/&gt;    &lt;/span&gt;EINT;&lt;br/&gt;    FCTL1 = FWKEY;                              &lt;span style="color: green"&gt;// Lock&lt;br/&gt;    &lt;/span&gt;FCTL3 = FWKEY + LOCK;                       &lt;span style="color: green"&gt;// Set Lock bit  &lt;br/&gt;&lt;/span&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;这个和上面给出的流程一样，参数是要被擦除的段的首地址。WaitForEnable函数等等待BUSY标志变回零即操作完成。&lt;/p&gt;    &lt;span style="color: blue"&gt;void &lt;/span&gt;WaitForEnable()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;while&lt;/span&gt;((FCTL3 &amp;amp; BUSY) == BUSY);      &lt;span style="color: green"&gt;//Busy&lt;br/&gt;&lt;/span&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;写入字节：&lt;/p&gt;    &lt;span style="color: blue"&gt;void &lt;/span&gt;FlashWriteChar(&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;addr,&lt;span style="color: blue"&gt;char &lt;/span&gt;Data)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;char &lt;/span&gt;*FlashPtr = (&lt;span style="color: blue"&gt;char &lt;/span&gt;*)addr;              &lt;span style="color: green"&gt;// Segment A pointer&lt;br/&gt;    &lt;/span&gt;FCTL1 = FWKEY + WRT;                        &lt;span style="color: green"&gt;// Set WRT bit for write operation&lt;br/&gt;    &lt;/span&gt;FCTL3 = FWKEY;                              &lt;span style="color: green"&gt;// Clear Lock bit&lt;br/&gt;    &lt;/span&gt;DINT;&lt;br/&gt;    *FlashPtr = Data;                           &lt;span style="color: green"&gt;// Save Data&lt;br/&gt;    &lt;/span&gt;WaitForEnable();                            &lt;span style="color: green"&gt;//Busy&lt;br/&gt;    &lt;/span&gt;EINT;&lt;br/&gt;    FCTL1 = FWKEY;                              &lt;span style="color: green"&gt;// Clear WRT bit&lt;br/&gt;    &lt;/span&gt;FCTL3 = FWKEY + LOCK;                       &lt;span style="color: green"&gt;// Set LOCK bit&lt;br/&gt;&lt;/span&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;写入字：&lt;/p&gt;    &lt;span style="color: blue"&gt;void &lt;/span&gt;FlashWriteWord(&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;addr,&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;Data)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;*FlashPtr = (&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;*)addr;&lt;br/&gt;    FCTL1 = FWKEY + WRT;                        &lt;span style="color: green"&gt;// Set WRT bit for write operation&lt;br/&gt;    &lt;/span&gt;FCTL3 = FWKEY;                              &lt;span style="color: green"&gt;// Clear Lock bit&lt;br/&gt;    &lt;/span&gt;DINT;&lt;br/&gt;    *FlashPtr = Data;                           &lt;span style="color: green"&gt;// Save Data&lt;br/&gt;    &lt;/span&gt;WaitForEnable();                            &lt;span style="color: green"&gt;//Busy&lt;br/&gt;    &lt;/span&gt;EINT;&lt;br/&gt;    FCTL1 = FWKEY;                              &lt;span style="color: green"&gt;// Clear WRT bit&lt;br/&gt;    &lt;/span&gt;FCTL3 = FWKEY + LOCK;                       &lt;span style="color: green"&gt;// Set LOCK bit&lt;br/&gt;&lt;/span&gt;}      &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;写入字或字节两个函数差别仅仅是指针类型不同。&lt;/p&gt;    &lt;p&gt;读取字或字节：&lt;/p&gt;    &lt;span style="color: blue"&gt;char &lt;/span&gt;FlashReadChar(&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;Addr)&lt;br/&gt;{ &lt;br/&gt;    &lt;span style="color: blue"&gt;char &lt;/span&gt;Data;&lt;br/&gt;    &lt;span style="color: blue"&gt;char &lt;/span&gt;*FlashPtr = (&lt;span style="color: blue"&gt;char &lt;/span&gt;*) Addr; &lt;br/&gt;    Data = *FlashPtr;&lt;br/&gt;    &lt;span style="color: blue"&gt;return&lt;/span&gt;(Data);&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;FlashReadWord(&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;Addr)&lt;br/&gt;{ &lt;br/&gt;    &lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;Data;&lt;br/&gt;    &lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;*FlashPtr = (&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;*)Addr; &lt;br/&gt;    Data = *FlashPtr;&lt;br/&gt;    &lt;span style="color: blue"&gt;return&lt;/span&gt;(Data);&lt;br/&gt;}     &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;这两个函数的差别也是仅仅指针类型不同。&lt;/p&gt;    &lt;p&gt;这些函数和前面硬件介绍部分的程序流程相同，这里不再详细说明。&lt;/p&gt;  &lt;/li&gt;  &lt;li&gt;&lt;strong&gt;使用示例：&lt;/strong&gt;&amp;#160; &lt;p&gt;使用方法和之前的一样，工程中加入C文件，源代码文件中文件包含H文件，即可使用，具体参考示例项目：&lt;/p&gt;    &lt;p&gt;演示主要程序主要如下：&lt;/p&gt;    &lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;lt;msp430x16x.h&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;Flash.h&amp;quot;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;int &lt;/span&gt;a;&lt;br/&gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;main( &lt;span style="color: blue"&gt;void &lt;/span&gt;)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: green"&gt;// Stop watchdog timer to prevent time out reset&lt;br/&gt;    &lt;/span&gt;WDTCTL = WDTPW + WDTHOLD;&lt;br/&gt;    ClkInit();&lt;br/&gt;    FlashInit();&lt;br/&gt;    FlashWriteChar(InfoB,0x25);&lt;br/&gt;    a=FlashReadChar (InfoB);        &lt;span style="color: green"&gt;//InfoB在H文件中有宏定义&lt;br/&gt;    &lt;/span&gt;FlashWriteWord(InfoB+2,0x5669);&lt;br/&gt;    a = FlashReadWord(InfoB+2);&lt;br/&gt;    FlashErase(InfoB);&lt;br/&gt;    LPM0;&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;这里向InfoB(1000h)首地址开始写数据，先写一个字节 再写入一个字（注意写入字时，必须是偶数地址，奇数地址会写在这个地址所在的前一个偶数地址），读出，然后擦除。这里的程序都是在Flash中运行的，没有演示RAM中运行的程序。如果在RAM运行程序，则需要先把程序从Flash中移到RAM中，然后跳转到RAM中运行。&lt;/p&gt;    &lt;p&gt;调试截图如下：&lt;/p&gt;    &lt;p&gt;&lt;a href="file:///C:/Documents and Settings/Administrator/Local Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image[7].png"&gt;&lt;img title="image_thumb[2]" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="317" alt="image_thumb[2]" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/20110831114125669.png" width="491" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;调试时，view-Memory菜单，调出存储器窗口；观察Flash内容。&lt;/p&gt;    &lt;p&gt;&lt;a href="file:///C:/Documents and Settings/Administrator/Local Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image[9].png"&gt;&lt;img title="image_thumb[4]" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="319" alt="image_thumb[4]" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108311141319835.png" width="495" border="0" /&gt;&lt;/a&gt;&lt;a href="file:///C:/Documents and Settings/Administrator/Local Settings/Temp/WindowsLiveWriter-267270020/supfiles59D70/image[3].png"&gt;&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;这里写入的是Info Flash部分，观察这部分的结果，和写入的结果同。&lt;/p&gt;  &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Flash程序控制器的程序就到这儿了。Flash可以用于存储长期保存的数据。有什么不足之处，欢迎讨论。&lt;/p&gt;&lt;p&gt;附件：&lt;a href="http://files.cnblogs.com/Engin/%E7%A8%8B%E5%BA%8F%E5%BA%93.rar"&gt;程序库&lt;/a&gt;&lt;/p&gt;&lt;p&gt;作者：&lt;b&gt;&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;给我一杯酒&lt;/a&gt;&lt;/b&gt;   &lt;br /&gt;出处：&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;http://Engin.cnblogs.com/&lt;/a&gt;   &lt;br /&gt;本文版权归作者和博客园共有，欢迎转载，转载保留此段文字并且注明出处；谢谢。 &lt;/p&gt;&lt;img src="http://www.cnblogs.com/Engin/aggbug/2160534.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/31/2160534.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Engin/archive/2011/08/29/2158284.html</id><title type="text">MSP430程序库&amp;lt;十四&amp;gt;DMA程序库</title><summary type="text">直接存储器存取(DMADirect Memory Access)方式是用硬件实现存储器与存储器之间或存储器与I\O设备之间直接进行高速数据传送，不需要CPU的干预。这种方式通常用来传送数据块。M...</summary><published>2011-08-29T07:50:00Z</published><updated>2011-08-29T07:50:00Z</updated><author><name>给我一杯酒</name><uri>http://www.cnblogs.com/Engin/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Engin/archive/2011/08/29/2158284.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Engin/archive/2011/08/29/2158284.html"/><content type="html">&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;直接存储器存取(DMADirect Memory Access)方式是用硬件实现存储器与存储器之间或存储器与I\O设备之间直接进行高速数据传送，不需要CPU的干预。这种方式通常用来传送数据块。MSP430f16x系列单片机内部含有DMA模块，而且几乎内部所有外设都可以触发DMA开始存取数据。这里实现了这个模块的程序通用的函数库，方便使用。&lt;/p&gt; &lt;/blockquote&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;硬件介绍：&lt;/strong&gt; &lt;/li&gt;    &lt;p&gt;MSP430F15X/16X 系列单片机具有DMA 控制器，从而能够为数据高速传输提供保证。例如，通过DMA控制器可以直接将ADC 转换存贮器的内容传到RAM 单元。&lt;/p&gt;    &lt;p&gt;MSP430系列单片机扩展的DMA具有来之所有外设的触发器，不需要CPU的干预即可提供先进的可配置的数据传输能力，从而加速了基于MCU的信号处理进程，DMA传输的触发来源对CPU 来说是完全透明的，DMA控制器可在内存与外部及外部硬件之间进行精确的传输控制。DMA 消除了数据传输延迟时间以及各种开销，从而可以解放16为RISC CPU，以便其将更多的时间用于处理数据，而非执行正在处理的任务。&lt;/p&gt;    &lt;p&gt;MSP430F16x系列单片机的DMA模块有以下特点：数据传送不需要CPU介入，完全由DMA控制器自行管理。在整个地址空间范围内传输数据，块方式传输可达65536字节；能够提高片内外设数据吞吐能力，实现高速传输，每个字或者字节的传输仅需要2个MCLK；减少系统功耗，即使在片内外设进行数据输入或输出时，CPU也可以处于超低功耗模式而不需唤醒；字节和字数据可以混合传送：DMA传输可以是字节到字节、字到字、字节到字或者字到字节。当字到字节传输时，只有字中较低字节能够传输，当从字节到字传输时，传输到字的低字节，高字节被自动清零；四种传输寻址模式：固定地址到固定地址、固定地址到块地址、块地址到固定地址以及块地址到块地址；触发方式灵活：边沿或者电平触发。单个、块或突发块传输模式：每次触发DMA操作，可以根据需要传输不同规模的数据&lt;/p&gt;    &lt;p&gt;DMA的四种寻址模式如下图所示：&lt;/p&gt;    &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108291549203747.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="376" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108291549223549.png" width="602" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;p&gt;DMA控制器模块：3个独立的传输通道：通道0、通道1和通道2。每个通道都有源地址寄存器、目的地址寄存器、传送数据长度寄存器和控制寄存器。每个通道的触发请求可以分别允许和禁止；可配置的通道优先权：优先权裁决模块，传输通道的优先级可以调整，对同时有触发请求的通道进行优先级裁决，确定哪个通道的优先级最高。MSP430的DMA控制器可以采用固定优先级，还可以采用循环优先级。程序命令控制模块，每个DMA通道开始传输之前，CPU要编程给定相关的命令和模式控制，以决定DMA通道传输的类型；可配置的传送触发器：触发源选择模块，DMAREQ（软件触发）、Timer_ACCR2输出、Timer_BCCR2输出、I2C 数据接收准备好、I2C 数据发送准备好、USART接收发送数据、DAC12模块DAC12IFG、ADC12模块的ADC12IFGx、DMAxIFG、DMAE0 外部触发源。并且还具有触发源扩充能力。&lt;/p&gt;    &lt;p&gt;DMA有六种传输模式：单字或者单字节传输；块传输；突发块传输；重复单字或者单字节传输；重复块传输；重复突发块传输。前三个，传输完成后DMAEN自动复位；再次传输时需要重新置位DMAEN位以使能DMA通道。后三个为重复模式，一次传输完成后，DMAEN不复位；再次出发时，可以再次启动数据传输。六种传输模式通过DMADTx寄存器设置：&lt;/p&gt;    &lt;span style="color: green"&gt;DMADTx      Transfer Mode               Description&lt;br/&gt;000         Single transfer             Each transfer requires a trigger. DMAEN is&lt;br/&gt;                                        automatically cleared when DMAxSZ transfers have&lt;br/&gt;                                        been made.&lt;br/&gt;001         Block transfer              A complete block is transferred with one trigger.&lt;br/&gt;                                        DMAEN is automatically cleared at the end of the&lt;br/&gt;                                        block transfer.&lt;br/&gt;010, 011    Burst-block transfer        CPU activity is interleaved with a block transfer.&lt;br/&gt;                                        DMAEN is automatically cleared at the end of the&lt;br/&gt;                                        burst-block transfer.&lt;br/&gt;100         Repeated single transfer    Each transfer requires a trigger. DMAEN remains&lt;br/&gt;                                        enabled.&lt;br/&gt;101         Repeated block transfer     A complete block is transferred with one trigger.&lt;br/&gt;                                        DMAEN remains enabled.&lt;br/&gt;110, 111    Repeated burst-block        CPU activity is interleaved with a block transfer.&lt;br/&gt;            transfer                    DMAEN remains enabled.&lt;br/&gt;&lt;/span&gt;  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;  &lt;p&gt;&lt;strong&gt;单字或者单字节传输&lt;/strong&gt;：DMA 通道被定义为单字或者单字节传输模式，每个字或者字节的传输都要触发信号触发。设置DMADTx=0 就定义了单字或者单字节传输模式，规定的传输完毕后DMAEN 位自动清除，如果需要再次传输，必须重新置位DMAEN。如果设置DMADTx＝4 为重复单字或者单字节传输模式，DMAEN 位一直保持置位，每次触发伴随一次传输。DMAxSZ 寄存器保存传输的单元个数，如果该寄存器为0，则没有传输。传输之前DMAxSZ 寄存器的值写入到一个临时的寄存器中，每次操作之后DMAxSZ 做减操作。当DMAxSZ减为零的时候，它所对应的临时寄存器将原来的值重新置入DMAxSZ，同时相应的DMAIFG标志置位。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;块传输模式&lt;/strong&gt;：在块传输模式，每次触发可以传输一个数据块。设置DMADTx=1 为块传输模式，每个数据块传输完毕，DMAEN 位自动清除，在触发传输下一个数据块之前，该位要被重新置位。在传输某个数据块期间，其他的传输请求将被忽略。设置DMADTx=5 为重复块传输模式，某个数据块传输完毕，DMAEN 位仍然保持置位，之后，新的触发可以引起又一次数据块传送。DMAxSZ 寄存器保存数据块所包含的单元个数。DMASRCINCR 和DMADSTINCR 反映在数据块传输过程中的目的地址和源地址的变化情况。在块传输或者重复块传输过程中，DMAxSA，DMAxDA，DMAxSZ 寄存器的值写入到对应的临时寄存器中，DMAxSA，DMAxDA寄存器所对应的临时值在块传输过程中增加或者减少，而DMAxSZ 在块传输过程中减计数，始终反映当前数据块还有多少单元没有传输完毕，当DMAxSZ 减为0，它所对应的临时寄存器将原来的值重新置入DMAxSZ，同时相应的DMAIFG被置位。在块传输过程中，CPU 暂停工作，不参与数据的传输。数据块需要2×MCLK×DMAxSZ 个时钟周期。当每个数据块传输完毕，CPU 按照暂停前的状态重新开始执行。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;突发块传输模式&lt;/strong&gt;：这个和块传输模式类似，只不过每传输4个字或字节，DMA释放内部总线，CPU运行2个MCLK周期；在传输过程中CPU有20%的执行时间，而块传输需要等DMA完全传送完之后，CPU方能运行。&lt;/p&gt;  &lt;p&gt;DMA触发源：每个通道的触发源有DMAxTSELx位进行控制的，这些位必须在DMAEN位为0是进行设置，否则可能出现不可预料的DMA触发。&lt;/p&gt;  &lt;span style="color: green"&gt;DMAxTSELx   Operation&lt;br/&gt;0000        DMAREQ bit (software trigger)&lt;br/&gt;0001        TACCR2 CCIFG bit&lt;br/&gt;0010        TBCCR2 CCIFG bit&lt;br/&gt;0011        URXIFG0 (UART/SPI mode), USART0 data received (I2C mode)&lt;br/&gt;0100        UTXIFG0 (UART/SPI mode), USART0 transmit ready (I2C mode)&lt;br/&gt;0101        DAC12_0CTL DAC12IFG bit&lt;br/&gt;0110        ADC12 ADC12IFGx bit&lt;br/&gt;0111        TACCR0 CCIFG bit&lt;br/&gt;1000        TBCCR0 CCIFG bit&lt;br/&gt;1001        URXIFG1 bit&lt;br/&gt;1010        UTXIFG1 bit&lt;br/&gt;1011        Multiplier ready&lt;br/&gt;1100        No action&lt;br/&gt;1101        No action&lt;br/&gt;1110        DMA0IFG bit triggers DMA channel 1&lt;br/&gt;            DMA1IFG bit triggers DMA channel 2&lt;br/&gt;            DMA2IFG bit triggers DMA channel 0&lt;br/&gt;1111        External trigger DMAE0&lt;br/&gt;&lt;/span&gt;  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;  &lt;p&gt;另外，单片机的中断程序不影响DMA的传输，当DMA传输过程中，单片机不响应中外部NMI中断(必须DMA的控制位ENNMI位为1时响应NMI中断，否则不予处理)外的所有中断；必须等待DMA数据传送结束之后才运行系统的中断处理程序。&lt;/p&gt;  &lt;p&gt;DMA的中断：数据传送过程中，DMAxSZ寄存器值减为0时，DMA置位DMAIFG，DMA的中断和DAC12模块共享中断向量，使用中断时需要软件判断具体是那个中断。中断响应后DMAIFG不会自动复位，使用时必须软件清零DMAIFG位。&lt;/p&gt;  &lt;p&gt;DMA的寄存器如下：&lt;/p&gt;  &lt;span style="color: green"&gt;Register                            Short Form      Register Type   Address     Initial State&lt;br/&gt;DMA control 0                       DMACTL0         Read/write      0122h       Reset with POR&lt;br/&gt;DMA control 1                       DMACTL1         Read/write      0124h       Reset with POR&lt;br/&gt;DMA channel 0 control               DMA0CTL         Read/write      01E0h       Reset with POR&lt;br/&gt;DMA channel 0 source address        DMA0SA          Read/write      01E2h       Unchanged&lt;br/&gt;DMA channel 0 destination address   DMA0DA          Read/write      01E4h       Unchanged&lt;br/&gt;DMA channel 0 transfer size         DMA0SZ          Read/write      01E6h       Unchanged&lt;br/&gt;DMA channel 1 control               DMA1CTL         Read/write      01E8h       Reset with POR&lt;br/&gt;DMA channel 1 source address        DMA1SA          Read/write      01EAh       Unchanged&lt;br/&gt;DMA channel 1 destination address   DMA1DA          Read/write      01ECh       Unchanged&lt;br/&gt;DMA channel 1 transfer size         DMA1SZ          Read/write      01EEh       Unchanged&lt;br/&gt;DMA channel 2 control               DMA2CTL         Read/write      01F0h       Reset with POR&lt;br/&gt;DMA channel 2 source address        DMA2SA          Read/write      01F2h       Unchanged&lt;br/&gt;DMA channel 2 destination address   DMA2DA          Read/write      01F4h       Unchanged&lt;br/&gt;DMA channel 2 transfer size         DMA2SZ          Read/write      01F6h       Unchanged&lt;br/&gt;&lt;/span&gt;  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;  &lt;p&gt;有关每个寄存器的详细内容参考ti提供的用户指南。&lt;/p&gt;  &lt;li&gt;&lt;strong&gt;程序实现：&lt;/strong&gt; &lt;/li&gt;  &lt;p&gt;DMA的使用主要是DMA寄存器的初始设置，设置完成后，DMA接到触发信号即可自动传输数据。&lt;/p&gt;  &lt;p&gt;设置函数如下：&lt;/p&gt;  &lt;span style="color: blue"&gt;void &lt;/span&gt;DMAInit(&lt;span style="color: blue"&gt;char &lt;/span&gt;channel,&lt;span style="color: blue"&gt;char &lt;/span&gt;trigger,&lt;span style="color: blue"&gt;char &lt;/span&gt;transMode,&lt;span style="color: blue"&gt;char &lt;/span&gt;srcMode,&lt;span style="color: blue"&gt;char &lt;/span&gt;dstMode,&lt;br/&gt;             &lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;src,&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;dst,&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;size)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;*DMAxCTL,*DMAxSA,*DMAxDA,*DMAxSZ;&lt;br/&gt;    &lt;br/&gt;    DMACTL0 = trigger &amp;lt;&amp;lt; (channel &amp;lt;&amp;lt; 2);&lt;br/&gt;    DMACTL1 = 0x04;         &lt;span style="color: green"&gt;//DMA收到触发请求时，等待当前指令执行完成后&lt;br/&gt;    &lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;switch &lt;/span&gt;(channel)        &lt;span style="color: green"&gt;//选择当前设置哪个DMA通道&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color: blue"&gt;case &lt;/span&gt;0: &lt;br/&gt;            DMAxCTL = (&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;*)&amp;amp;DMA0CTL;&lt;br/&gt;            DMAxSA = (&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;*)&amp;amp;DMA0SA;&lt;br/&gt;            DMAxDA = (&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;*)&amp;amp;DMA0DA;&lt;br/&gt;            DMAxSZ = (&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;*)&amp;amp;DMA0SZ;&lt;br/&gt;            &lt;span style="color: blue"&gt;break&lt;/span&gt;;                                      &lt;span style="color: green"&gt;//指针 = 0通道控制&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;case &lt;/span&gt;1: &lt;br/&gt;            DMAxCTL = (&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;*)&amp;amp;DMA1CTL;&lt;br/&gt;            DMAxSA = (&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;*)&amp;amp;DMA1SA;&lt;br/&gt;            DMAxDA = (&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;*)&amp;amp;DMA1DA;&lt;br/&gt;            DMAxSZ = (&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;*)&amp;amp;DMA1SZ;&lt;br/&gt;            &lt;span style="color: blue"&gt;break&lt;/span&gt;;                                      &lt;span style="color: green"&gt;//指针 = 1通道控制&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;case &lt;/span&gt;2: &lt;br/&gt;            DMAxCTL = (&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;*)&amp;amp;DMA2CTL;&lt;br/&gt;            DMAxSA = (&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;*)&amp;amp;DMA2SA;&lt;br/&gt;            DMAxDA = (&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;*)&amp;amp;DMA2DA;&lt;br/&gt;            DMAxSZ = (&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;*)&amp;amp;DMA2SZ;&lt;br/&gt;            &lt;span style="color: blue"&gt;break&lt;/span&gt;;                                      &lt;span style="color: green"&gt;//指针 = 2通道控制&lt;br/&gt;    &lt;/span&gt;}&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color: blue"&gt;switch &lt;/span&gt;(transMode)      &lt;span style="color: green"&gt;//设置DMA通道的传输模式&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'S'&lt;/span&gt;: *DMAxCTL = DMADT_0;   &lt;span style="color: blue"&gt;break&lt;/span&gt;;          &lt;span style="color: green"&gt;//单次传输&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'s'&lt;/span&gt;: *DMAxCTL = DMADT_4;   &lt;span style="color: blue"&gt;break&lt;/span&gt;;          &lt;span style="color: green"&gt;//重复单次传输&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'B'&lt;/span&gt;: *DMAxCTL = DMADT_1;   &lt;span style="color: blue"&gt;break&lt;/span&gt;;          &lt;span style="color: green"&gt;//块传输&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'b'&lt;/span&gt;: *DMAxCTL = DMADT_5;   &lt;span style="color: blue"&gt;break&lt;/span&gt;;          &lt;span style="color: green"&gt;//重复块传输&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'I'&lt;/span&gt;: *DMAxCTL = DMADT_2;   &lt;span style="color: blue"&gt;break&lt;/span&gt;;          &lt;span style="color: green"&gt;//突发块传输 交错&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'i'&lt;/span&gt;: *DMAxCTL = DMADT_6;   &lt;span style="color: blue"&gt;break&lt;/span&gt;;          &lt;span style="color: green"&gt;//重复突发块传输 交错&lt;br/&gt;    &lt;/span&gt;}&lt;br/&gt;    &lt;br/&gt;    *DMAxCTL |= (srcMode &amp;amp; 0x04) &amp;lt;&amp;lt; 2;                  &lt;span style="color: green"&gt;//源 字或字节&lt;br/&gt;    &lt;/span&gt;*DMAxCTL |= (srcMode &amp;amp; 0x03) &amp;lt;&amp;lt; 8;                  &lt;span style="color: green"&gt;//源 地址改变方式&lt;br/&gt;    &lt;br/&gt;    &lt;/span&gt;*DMAxCTL |= (dstMode &amp;amp; 0x04) &amp;lt;&amp;lt; 3;                  &lt;span style="color: green"&gt;//目的 字或字节&lt;br/&gt;    &lt;/span&gt;*DMAxCTL |= (dstMode &amp;amp; 0x03) &amp;lt;&amp;lt; 10;                 &lt;span style="color: green"&gt;//目的 地址改变方式&lt;br/&gt;    &lt;br/&gt;    &lt;/span&gt;*DMAxSA = src;&lt;br/&gt;    *DMAxDA = dst;&lt;br/&gt;    *DMAxSZ = size;&lt;br/&gt;    &lt;br/&gt;    *DMAxCTL |= DMAEN;                                  &lt;span style="color: green"&gt;//DMA使能&lt;br/&gt;&lt;/span&gt;}  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;  &lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;函数比较麻烦，函数内容按参数设置每个寄存器。DMACTL0 = trigger &amp;lt;&amp;lt; (channel &amp;lt;&amp;lt; 2); 这个是设置对应channel通道的的参考源，不大明白的可以看下DMACTL0的寄存器内容；&lt;span style="color: blue"&gt;switch (&lt;/span&gt;channel)语句则根据通道设置对应指针指向的寄存器；然后对应设置参数即可。&lt;/p&gt;  &lt;p&gt;当设置成非重复模式时，需要重新置位DMAEN，本程序就函数DMAReEnable实现：&lt;/p&gt;  &lt;span style="color: blue"&gt;void &lt;/span&gt;DMAReEnable(&lt;span style="color: blue"&gt;char &lt;/span&gt;channel)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;switch &lt;/span&gt;(channel)        &lt;span style="color: green"&gt;//使能对应通道&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color: blue"&gt;case &lt;/span&gt;0: DMA0CTL |= DMAEN;   &lt;span style="color: blue"&gt;break&lt;/span&gt;;      &lt;span style="color: green"&gt;//0通道&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;case &lt;/span&gt;1: DMA1CTL |= DMAEN;   &lt;span style="color: blue"&gt;break&lt;/span&gt;;      &lt;span style="color: green"&gt;//1通道&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;case &lt;/span&gt;2: DMA2CTL |= DMAEN;   &lt;span style="color: blue"&gt;break&lt;/span&gt;;      &lt;span style="color: green"&gt;//2通道&lt;br/&gt;    &lt;/span&gt;}&lt;br/&gt;}  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;  &lt;p&gt;这个函数比较简单，只是根据传入参数设置对应通道的DMAEN位。&lt;/p&gt;  &lt;p&gt;当设置为软件触发时，需要软件启动DMA程序如下：&lt;/p&gt;  &lt;span style="color: blue"&gt;void &lt;/span&gt;DMAStart(&lt;span style="color: blue"&gt;char &lt;/span&gt;channel)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;switch &lt;/span&gt;(channel)        &lt;span style="color: green"&gt;//使能对应通道&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color: blue"&gt;case &lt;/span&gt;0: DMA0CTL |= DMAREQ;  &lt;span style="color: blue"&gt;break&lt;/span&gt;;      &lt;span style="color: green"&gt;//0通道&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;case &lt;/span&gt;1: DMA1CTL |= DMAREQ;  &lt;span style="color: blue"&gt;break&lt;/span&gt;;      &lt;span style="color: green"&gt;//1通道&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;case &lt;/span&gt;2: DMA2CTL |= DMAREQ;  &lt;span style="color: blue"&gt;break&lt;/span&gt;;      &lt;span style="color: green"&gt;//2通道&lt;br/&gt;    &lt;/span&gt;}&lt;br/&gt;}  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;  &lt;p&gt;这个和上个函数类似：仅仅设置一个控制位，函数很简单，不再解释啦。&lt;/p&gt;  &lt;p&gt;程序实现就这么多了，有关详细内容可以下载附件里的程序库，程序的注释很详细。&lt;/p&gt;  &lt;li&gt;&lt;strong&gt;使用示例：&lt;/strong&gt; &lt;/li&gt;  &lt;p&gt;使用这个程序时，步骤和原来的相同：工程中加入DMA.c文件，然后源文件中包含DMA.h头文件即可。&lt;/p&gt;  &lt;p&gt;示例程序主要如下：&lt;/p&gt;  &lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;lt;msp430x16x.h&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;DMA.h&amp;quot;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;a[5] = {8693,5689,2356,23565,5656};&lt;br/&gt;&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;b[5];&lt;br/&gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;main( &lt;span style="color: blue"&gt;void &lt;/span&gt;)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: green"&gt;// Stop watchdog timer to prevent time out reset&lt;br/&gt;    &lt;/span&gt;WDTCTL = WDTPW + WDTHOLD;&lt;br/&gt;    ClkInit();&lt;br/&gt;    &lt;span style="color: green"&gt;//块传输，5个字（16位） a-&amp;gt;b&lt;br/&gt;    &lt;/span&gt;DMAInit(0,0x00,&lt;span style="color: #a31515"&gt;'B'&lt;/span&gt;,3,3,(&lt;span style="color: blue"&gt;unsigned int&lt;/span&gt;)a,(&lt;span style="color: blue"&gt;unsigned int&lt;/span&gt;)b,5);&lt;br/&gt;    DMAStart(0);&lt;br/&gt;    &lt;span style="color: green"&gt;//如果需要再次传输 而不改变设置，只需调用DMAReEnable再次启动传输即可 &lt;br/&gt;    // 如果是重复块传输，则不需要重新使能DMAReEnable 直接启动即可&lt;br/&gt;    //这里仅仅演示了使用方法，实际应用中，应根据需要选择适当的触发源。&lt;br/&gt;    //&lt;br/&gt;    &lt;/span&gt;LPM0;&lt;br/&gt;}  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;  &lt;p&gt;示例程序完成功能很简单，仅仅把一个数组的值赋给另外一个数组。数组地址即是数组名强制转换为所需类型(无符号16位)，传入函数初始化设置。这里为了简便，设置为软件启动。&lt;/p&gt;  &lt;p&gt;运行效果如下：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/20110829154926578.png"&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="321" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/20110829154929248.png" width="485" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;单步运行完启动DMA传输后，结果即出来了；说明DMA传输数据的速度是很快的。&lt;/p&gt;&lt;/ol&gt;&lt;p&gt;DMA可以用于对速度要求比较高的程序中。例如：DMA配合硬件乘法器和ADC12模块，可以很容易的实现比较高频率的数字滤波方案。&lt;/p&gt;&lt;p&gt;附件：&lt;a href="http://files.cnblogs.com/Engin/%E7%A8%8B%E5%BA%8F%E5%BA%93.rar"&gt;程序库&lt;/a&gt;&lt;/p&gt;&lt;p&gt;作者：&lt;b&gt;&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;给我一杯酒&lt;/a&gt;&lt;/b&gt;     &lt;br /&gt;出处：&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;http://Engin.cnblogs.com/&lt;/a&gt;     &lt;br /&gt;本文版权归作者和博客园共有，欢迎转载，转载保留此段文字并且注明出处；谢谢。 &lt;/p&gt;&lt;img src="http://www.cnblogs.com/Engin/aggbug/2158284.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/29/2158284.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Engin/archive/2011/08/28/2156346.html</id><title type="text">MSP430程序库&amp;lt;十三&amp;gt;硬件乘法器使用</title><summary type="text">硬件乘法器不占用CPU周期，有硬件实现，速度比软件实现的乘法速度快很多。msp430f14x、msp430f16x中都含有硬件乘法器模块，方便用户需要速度的时候使用。 硬件介绍： ...</summary><published>2011-08-28T11:54:00Z</published><updated>2011-08-28T11:54:00Z</updated><author><name>给我一杯酒</name><uri>http://www.cnblogs.com/Engin/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Engin/archive/2011/08/28/2156346.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Engin/archive/2011/08/28/2156346.html"/><content type="html">&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;硬件乘法器不占用CPU周期，有硬件实现，速度比软件实现的乘法速度快很多。msp430f14x、msp430f16x中都含有硬件乘法器模块，方便用户需要速度的时候使用。&lt;/p&gt; &lt;/blockquote&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;硬件介绍：&lt;/strong&gt;       &lt;p&gt;在MSP430系列单片机中，硬件乘法器是外围模块，而不是CPU内核的一部分；所以它的活动与否与CPU的活动与否无关，它的寄存器和其他的外围寄存器一样通过CPU指令读写。&lt;/p&gt;      &lt;p&gt;硬件乘法器模块支持一下功能：无符号乘法、有符号乘法、无符号乘加、有符号乘加；可以支持16*16 16*8 8*16 8*8bits的乘法。&lt;/p&gt;      &lt;p&gt;硬件乘法器的模块框图如下：&lt;/p&gt;      &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108281951297374.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="519" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108281951341796.png" width="680" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;      &lt;p&gt;硬件乘法器模块的四种操作类型(无符号乘法、有符号乘法、无符号乘加、有符号乘加)是由写入的第一个操作数的位置决定的。这个模块有两个操作数寄存器：OP1和OP2、三个结果寄存器RESLO, RESHI, 和SUMEXT。RESLO寄存器存储结果的低字(低16位)；RESHI寄存器存储结果的高字(高16位)；SUMEXT寄存器存储结果的有关信息。结果在3个时钟周期后即可完成；写入OP2后的下一条指令即可读取结果，有一种情况例外：用间接寻址方式访问结果。用间接寻址方式访问结果时，读取结果之前需要有一条NOP指令。&lt;/p&gt;      &lt;p&gt;操作数OP1有四个地址(MPY:0130h MPYS:0132h MAC:0134h MACS:0136h)，这四个寄存器用来选择乘法的操作模式。写入第一个操作数寄存器决定用哪种操作：无符号 用符号等，但是不启动相乘操作；写入第二个操作数寄存器启动相乘的操作。计算完成后结果存入寄存器RESLO,RESHI, 和SUMEXT。&lt;/p&gt;      &lt;p&gt;操作数1的四个地址对应的操作：&lt;/p&gt;      &lt;span style="color: green"&gt;OP1 Address Register Name   Operation&lt;br/&gt;0130h       MPY             Unsigned multiply（无符号乘法）&lt;br/&gt;0132h       MPYS            Signed multiply（有符号乘法）&lt;br/&gt;0134h       MAC             Unsigned multiply accumulate（无符号乘加）&lt;br/&gt;0136h       MACS            Signed multiply accumulate（有符号乘加）&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;四种操作模式下高位结果寄存器的内容如下：&lt;/p&gt;    &lt;span style="color: green"&gt;Mode        RESHI Contents&lt;br/&gt;MPY         Upper 16-bits of the result&lt;br/&gt;MPYS        The MSB is the sign of the result. The remaining bits are the upper&lt;br/&gt;            15-bits of the result. Two’s complement notation is usedfor the result.&lt;br/&gt;MAC         Upper 16-bits of the result&lt;br/&gt;MACS        Upper 16-bits of the result. Two’s complement notation is used for the result.&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;四种操作模式SUMEXT 寄存器的内容：&lt;/p&gt;    &lt;span style="color: green"&gt;Mode        SUMEXT&lt;br/&gt;MPY         SUMEXT is always 0000h&lt;br/&gt;MPYS        SUMEXT contains the extended sign of the result&lt;br/&gt;            00000h Result was positive or zero&lt;br/&gt;            0FFFFh Result was negative&lt;br/&gt;MAC         SUMEXT contains the carry of the result&lt;br/&gt;            0000h No carry for result&lt;br/&gt;            0001h Result has a carry&lt;br/&gt;MACS        SUMEXT contains the extended sign of the result&lt;br/&gt;            00000h Result was positive or zero&lt;br/&gt;            0FFFFh Result was negative&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;连续乘法运算时，如果操作数1不需改变就可以运算，则可以不需要重新写入和以保存内容相同的数；但OP2必须重新写入以启动乘法运算。&lt;/p&gt;    &lt;p&gt;MACS Underflow and Overflow（MACS时的上溢和下溢）：硬件乘法器不检测有符号乘加时运算结果的上溢出和下溢出。结果的正数范围：0到7FFF FFFFh；负数范围：0FFFF FFFFh到8000 0000h。下溢出是两个负数的和结果寄存器得到的是正数，上溢出是两个正数的和结果寄存器得到的是负数。SUMEXT寄存器存储有结果的符号，可以根据它判断是否溢出（0000h 负数和 则上溢 0FFFFh 正数和 则下溢）。使用时 程序必须合适的检测、处理MACS的溢出情况。&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;程序示例(用户指南上给出的汇编示例)：&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;所有乘数模式的例子如下。所有的8x8模式使用的寄存器的绝对地址，因为汇编器将不允许B访问到字寄存器时使用标准定义的文件标签。&lt;/p&gt;    &lt;span style="color: green"&gt;; 16x16 Unsigned Multiply&lt;br/&gt;&lt;/span&gt;MOV #01234h,&amp;amp;MPY&lt;span style="color: green"&gt; ; Load first operand&lt;br/&gt;&lt;/span&gt;MOV #05678h,&amp;amp;OP2&lt;span style="color: green"&gt; ; Load second operand&lt;br/&gt;; ... ; Process results&lt;br/&gt;; 8x8 Unsigned Multiply. Absolute addressing.&lt;br/&gt;&lt;/span&gt;MOV.B #012h,&amp;amp;0130h &lt;span style="color: green"&gt;; Load first operand&lt;br/&gt;&lt;/span&gt;MOV.B #034h,&amp;amp;0138h&lt;span style="color: green"&gt; ; Load 2nd operand&lt;br/&gt;; ... ; Process results&lt;br/&gt;; 16x16 Signed Multiply&lt;br/&gt;&lt;/span&gt;MOV #01234h,&amp;amp;MPYS &lt;span style="color: green"&gt;; Load first operand&lt;br/&gt;&lt;/span&gt;MOV #05678h,&amp;amp;OP2&lt;span style="color: green"&gt; ; Load 2nd operand&lt;br/&gt;; ... ; Process results&lt;br/&gt;; 8x8 Signed Multiply. Absolute addressing.&lt;br/&gt;&lt;/span&gt;MOV.B #012h,&amp;amp;0132h&lt;span style="color: green"&gt; ; Load first operand&lt;br/&gt;&lt;/span&gt;SXT &amp;amp;MPYS&lt;span style="color: green"&gt; ; Sign extend first operand&lt;br/&gt;&lt;/span&gt;MOV.B #034h,&amp;amp;0138h &lt;span style="color: green"&gt;; Load 2nd operand&lt;br/&gt;&lt;/span&gt;SXT &amp;amp;OP2&lt;span style="color: green"&gt; ; Sign extend 2nd operand&lt;br/&gt;; (triggers 2nd multiplication)&lt;br/&gt;; ... ; Process results&lt;br/&gt;; 16x16 Unsigned Multiply Accumulate&lt;br/&gt;&lt;/span&gt;MOV #01234h,&amp;amp;MAC &lt;span style="color: green"&gt;; Load first operand&lt;br/&gt;&lt;/span&gt;MOV #05678h,&amp;amp;OP2 &lt;span style="color: green"&gt;; Load 2nd operand&lt;br/&gt;; ... ; Process results&lt;br/&gt;; 8x8 Unsigned Multiply Accumulate. Absolute addressing&lt;br/&gt;&lt;/span&gt;MOV.B #012h,&amp;amp;0134h &lt;span style="color: green"&gt;; Load first operand&lt;br/&gt;&lt;/span&gt;MOV.B #034h,&amp;amp;0138h&lt;span style="color: green"&gt; ; Load 2nd operand&lt;br/&gt;; ... ; Process results&lt;br/&gt;; 16x16 Signed Multiply Accumulate&lt;br/&gt;&lt;/span&gt;MOV #01234h,&amp;amp;MACS&lt;span style="color: green"&gt; ; Load first operand&lt;br/&gt;&lt;/span&gt;MOV #05678h,&amp;amp;OP2 &lt;span style="color: green"&gt;; Load 2nd operand&lt;br/&gt;; ... ; Process results&lt;br/&gt;; 8x8 Signed Multiply Accumulate. Absolute addressing&lt;br/&gt;&lt;/span&gt;MOV.B #012h,&amp;amp;0136h&lt;span style="color: green"&gt; ; Load first operand&lt;br/&gt;&lt;/span&gt;SXT &amp;amp;MACS &lt;span style="color: green"&gt;; Sign extend first operand&lt;br/&gt;&lt;/span&gt;MOV.B #034h,R5 &lt;span style="color: green"&gt;; Temp. location for 2nd operand&lt;br/&gt;&lt;/span&gt;SXT R5 &lt;span style="color: green"&gt;; Sign extend 2nd operand&lt;br/&gt;&lt;/span&gt;MOV R5,&amp;amp;OP2 &lt;span style="color: green"&gt;; Load 2nd operand&lt;br/&gt;; ... ; Process results&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;上面的程序虽然和标准的汇编差异比较大，但是有一定汇编基础的人还是很容易就能够看懂。这里的程序给出了多种方式写入操作数寄存器。&lt;/p&gt;    &lt;p&gt;间接寻址结果寄存器时，在写入OP2操作数启动乘法后，至少需要一个指令的延迟后才能访问结果寄存器RESLO等；直接寻址时可以写入OP2后，下一条指令即可读取结果。示例程序（汇编）：&lt;/p&gt;    &lt;span style="color: green"&gt;; Access multiplier results with indirect addressing&lt;br/&gt;&lt;/span&gt;MOV #RESLO,R5 &lt;span style="color: green"&gt;; RESLO address in R5 for indirect&lt;br/&gt;&lt;/span&gt;MOV &amp;amp;OPER1,&amp;amp;MPY &lt;span style="color: green"&gt;; Load 1st operand&lt;br/&gt;&lt;/span&gt;MOV &amp;amp;OPER2,&amp;amp;OP2&lt;span style="color: green"&gt; ; Load 2nd operand&lt;br/&gt;&lt;/span&gt;NOP&lt;span style="color: green"&gt; ; Need one cycle 写入两个操作数 乘法运算开始后 需要一个NOP&lt;br/&gt;&lt;/span&gt;MOV @R5+,&amp;amp;xxx&lt;span style="color: green"&gt; ; Move RESLO&lt;br/&gt;&lt;/span&gt;MOV @R5,&amp;amp;xxx &lt;span style="color: green"&gt;; Move RESHI&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;如果在写入OP1和写入OP2之间产生了中断，中断响应后，源操作数的计算模式丢失；运算结果不确定。为了避免这种情况的发生，在写入操作数时禁止中断或在中断响应函数中不使用硬件乘法器。如：&lt;/p&gt;    &lt;span style="color: green"&gt;; Disable interrupts before using the hardware multiplier&lt;br/&gt;&lt;/span&gt;DINT &lt;span style="color: green"&gt;; Disable interrupts&lt;br/&gt;&lt;/span&gt;NOP &lt;span style="color: green"&gt;; Required for DINT&lt;br/&gt;&lt;/span&gt;MOV #xxh,&amp;amp;MPY &lt;span style="color: green"&gt;; Load 1st operand&lt;br/&gt;&lt;/span&gt;MOV #xxh,&amp;amp;OP2 &lt;span style="color: green"&gt;; Load 2nd operand&lt;br/&gt;&lt;/span&gt;EINT &lt;span style="color: green"&gt;; Interrupts may be enable before&lt;br/&gt;; Process results&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;硬件部分就说这么多了，有什么不大明白的可以参考用户指南。&lt;/p&gt;  &lt;/li&gt;  &lt;li&gt;&lt;strong&gt;使用示例：&lt;/strong&gt;     &lt;p&gt;我的程序仅仅是用C语言演示硬件乘法器的使用。程序主要内容如下：&lt;/p&gt;    &lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;lt;msp430x16x.h&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: green"&gt;/****************************************************************************&lt;br/&gt;* 名    称：main主程序&lt;br/&gt;* 功    能：硬件乘法器程序库使用演示&lt;br/&gt;* 入口参数：无&lt;br/&gt;* 出口参数：无&lt;br/&gt;****************************************************************************/&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;main( &lt;span style="color: blue"&gt;void &lt;/span&gt;)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: green"&gt;// Stop watchdog timer to prevent time out reset&lt;br/&gt;    &lt;/span&gt;WDTCTL = WDTPW + WDTHOLD;&lt;br/&gt;    ClkInit();&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color: green"&gt;/*把 硬件乘法器的寄存器放到watch窗口 观察是否变化&lt;br/&gt;    int a = 0;&lt;br/&gt;    a=  5*6;&lt;br/&gt;    */&lt;br/&gt;    //测试无符号乘法&lt;br/&gt;    &lt;/span&gt;MPY = 65535;&lt;br/&gt;    OP2 = 2;&lt;br/&gt;    &lt;span style="color: green"&gt;//有符号乘法&lt;br/&gt;    &lt;/span&gt;MPYS = 65535;&lt;br/&gt;    OP2 = 2;&lt;br/&gt;    &lt;span style="color: green"&gt;//无符号乘加&lt;br/&gt;    &lt;/span&gt;MAC = 65535;&lt;br/&gt;    OP2 = 2;&lt;br/&gt;    &lt;span style="color: green"&gt;//有符号乘加&lt;br/&gt;    &lt;/span&gt;MACS = 65535;&lt;br/&gt;    OP2 = 2;&lt;br/&gt;    LPM0;&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;程序演示了4中乘法模式：使用时单步调试，观察硬件乘法器的有关寄存器。如：&lt;/p&gt;    &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108281952387535.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="263" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/20110828195301665.png" width="526" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;p&gt;硬件乘法器运算速度很快，只需3个时钟周期；这里IAR单步调试时，OP2赋值结束，在watch窗口马上就可以看到运算结果。其他三种模式类似。&lt;/p&gt;    &lt;p&gt;注释掉的这部分是我用来检测IAR编译程序是否使用硬件乘法器进行测试。默认情况下，乘法应该是用硬件乘法器运算的。默认的设置如下：&lt;/p&gt;    &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/20110828195312937.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="354" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/20110828195314673.png" width="416" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;p&gt;硬件乘法器是选中的，这时应该是使用硬件乘法器的，但是我的调试结果显示它没有使用硬件乘法器，截图下：&lt;/p&gt;    &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108281953332836.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="226" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108281953352049.png" width="561" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;运行后乘法器相关位没有对应变化，如果使用的话，应该变化。&lt;/p&gt;    &lt;p&gt;硬件乘法器不选中时，寄存器也没有相应变化，从这看，IAR没有使用硬件乘法器；也许程序没有优化太多或是debug版本不使用硬件乘法器。&lt;/p&gt;    &lt;p&gt;如果需要直接使用硬件乘法器，有必要时把设置的硬件乘法器去掉，以防冲突。&lt;/p&gt;    &lt;p&gt;下面是直接使用硬件乘法器的一个实例：&lt;/p&gt;    &lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;msp430x16x.h&amp;quot;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;Result[7];&lt;br/&gt;&lt;span style="color: blue"&gt;unsigned char &lt;/span&gt;Data1[7];&lt;br/&gt;&lt;span style="color: blue"&gt;unsigned char &lt;/span&gt;Data2[7];&lt;br/&gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;main(&lt;span style="color: blue"&gt;void&lt;/span&gt;)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;unsigned char &lt;/span&gt;i;&lt;br/&gt;    WDTCTL = WDTPW + WDTHOLD; &lt;span style="color: green"&gt;// 关看门狗&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;for&lt;/span&gt;(i=0; i&amp;lt;7; i++)&lt;br/&gt;    {&lt;br/&gt;        Data1[i] = 10 * i; &lt;span style="color: green"&gt;// 对两数组赋值&lt;br/&gt;        &lt;/span&gt;Data2[i] = 25 * i;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: blue"&gt;for&lt;/span&gt;(i=0; i&amp;lt;7; i++)&lt;br/&gt;    {&lt;br/&gt;        MPY = Data1[i];&lt;br/&gt;        OP2 = Data2[i];&lt;br/&gt;        _NOP(); &lt;span style="color: green"&gt;// 延迟&lt;br/&gt;        &lt;/span&gt;_NOP();&lt;br/&gt;        _NOP();&lt;br/&gt;        Result[i] = RESLO; &lt;span style="color: green"&gt;// 保存结果，由于是8×8型，所以未用到RESHI；&lt;br/&gt;    &lt;/span&gt;}&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;这个程序用无符号乘法运算，结果存入结果数组中。值的注意的是程序中的3个NOP，这里NOP不需要，根据头文件推测，IAR编译器应该使用的是直接寻址方式，可以不要。如果不太放心，一个NOP即可，即便用的是间接寻址，一个NOP的延迟已经足够。&lt;/p&gt;  &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;硬件乘法器一般不会像上面的程序那么使用，如果这样就太浪费了；还不如直接用 *操作符来的简便；硬件乘法器主要用来对时间要求苛刻的情况。如：用430进行数字滤波，快速傅里叶变换等。ti有一篇应用笔记介绍的就是用msp430f169实现数字滤波方案。&lt;/p&gt;&lt;p&gt;硬件乘法器就到这里了，希望对大家有所帮助。有什么不足之处，欢迎拍砖讨论。&lt;/p&gt;&lt;p&gt;附件：&lt;a href="http://files.cnblogs.com/Engin/%E7%A8%8B%E5%BA%8F%E5%BA%93.rar"&gt;程序库&lt;/a&gt;&lt;/p&gt;&lt;p&gt;作者：&lt;b&gt;&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;给我一杯酒&lt;/a&gt;&lt;/b&gt;   &lt;br /&gt;出处：&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;http://Engin.cnblogs.com/&lt;/a&gt;   &lt;br /&gt;本文版权归作者和博客园共有，欢迎转载，转载保留此段文字并且注明出处；谢谢。 &lt;/p&gt;&lt;img src="http://www.cnblogs.com/Engin/aggbug/2156346.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/28/2156346.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Engin/archive/2011/08/28/2156007.html</id><title type="text">MSP430程序库&amp;lt;十二&amp;gt;SVS(电源电压监控器)模块</title><summary type="text">电源电压监控对于单片机来说，也是经常要用的模块。当需要稳定的工业级产品时，经常要对电源电压监控，以保证单片机系统工作于正常环境或范围中。MSP430F16x提供了一个现成的电源电压监控器模块...</summary><published>2011-08-28T03:38:00Z</published><updated>2011-08-28T03:38:00Z</updated><author><name>给我一杯酒</name><uri>http://www.cnblogs.com/Engin/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Engin/archive/2011/08/28/2156007.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Engin/archive/2011/08/28/2156007.html"/><content type="html">&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;电源电压监控对于单片机来说，也是经常要用的模块。当需要稳定的工业级产品时，经常要对电源电压监控，以保证单片机系统工作于正常环境或范围中。MSP430F16x提供了一个现成的电源电压监控器模块SVS，方便检测电源电压或者是外部电压，可以设置为电压过低时复位 或置标志位。本程序即完成SVS的设置使用的程序库(msp430f14x没有此模块)。&lt;/p&gt;&lt;/blockquote&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;硬件介绍：&lt;/strong&gt;&lt;p&gt;MSP430单片机含有的SVS模块可以很方便的监控电源电压或外部电压。&lt;/p&gt;&lt;p&gt;电源电压监控器（SVS）是用于监控AVCC电源电压或外部电压。 SVS的可配置当电源电压或外部电压下降到低于用户选择的电压级别时设置一个标志，或产生POR复位。&lt;/p&gt;&lt;p&gt;SVS模块有以下特点：可以监控AVCC电压；可选择产生复位信号；可软件设置SVS比较器输出信号；低电压标志可以被锁定或被用户程序访问；有14个可供选择的电压门限；可以监控外部输入电压。SVS模块可以很方便的监控电源电压或系统的其他电压，可以产生复位信号或是置标志位。&lt;/p&gt;&lt;p&gt;SVS模块仅有一个8位的寄存器，使用十分方便。寄存器SVSCTL：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108281137244054.png"&gt;&lt;img title="image" style="display: inline; border-width: 0px;" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108281138194862.png" border="0" height="88" width="464" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;高四位VLDx用来设置监控电源电压的门限、关闭SVS或者选择监控外部输入电压。具体含义如下：&lt;/p&gt;    &lt;span style="color: green;"&gt;0000 SVS is off     0001 1.9 V 检测AVCC是否低于1.9v,以下类似&lt;br/&gt;    0010 2.1 V          0011 2.2 V&lt;br/&gt;    0100 2.3 V          0101 2.4 V&lt;br/&gt;    0110 2.5 V          0111 2.65 V&lt;br/&gt;    1000 2.8 V          1001 2.9 V&lt;br/&gt;    1010 3.05           1011 3.2 V&lt;br/&gt;    1100 3.35 V         1101 3.5 V&lt;br/&gt;    1110 3.7 V&lt;br/&gt;    1111 检测由SVSIN引脚输入的电压是否低于1.2 V.&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;当高四位是 0时，SVS模块是关闭的；1-14分别是对电源电压监控的14个门限电压；15时，监控外部电压，门限电压是1.2v。&lt;/p&gt;&lt;p&gt;PORON位设置是否启动电压低于门限时，单片机复位：1 复位 0 置标志位SVSFG&lt;/p&gt;&lt;p&gt;SVSON位，这位和其他模块的ON位不太一样，SVSON位仅仅指示当前SVS模块是否打开，而不是用来开关模块的。&lt;/p&gt;&lt;p&gt;SVSOP位，这位是设置SVS内部比较器输出值：0 输出低电平 1 输出高电平。&lt;/p&gt;&lt;p&gt;SVSFG位，标志位 指示是否检测到低电压 仅PORON 为0时有效 出现低电压后置1；改为不会自动清零，必须软件清零。&lt;/p&gt;&lt;p&gt;另外，SVS模块值得一提的是：SVS门限电压已经设置回差带：每个SVS的水平已经滞后AVCC，接近临界值时，以减少小型电源电压的变化的敏感性。 SVS的操作和SVS /掉电互操作如图：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108281138243778.png"&gt;&lt;img title="image" style="display: inline; border-width: 0px;" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108281138271910.png" border="0" height="469" width="673" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;如图：为防止电压在门限附近变动时，SVS过于敏感，每个门限附近都有回差带。这样SVS模块用起来更好用。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;程序实现：&lt;/strong&gt;&lt;p&gt;程序主要是对SVS模块寄存器SVSCTL的设置和检测。首先是设置SVS函数：&lt;/p&gt;&lt;span style="color: blue;"&gt;void &lt;/span&gt;SVSSetup(&lt;span style="color: blue;"&gt;char &lt;/span&gt;voltageLevel,&lt;span style="color: blue;"&gt;char &lt;/span&gt;reset)&lt;br/&gt;{&lt;br/&gt;    SVSCTL = voltageLevel &amp;lt;&amp;lt; 4;&lt;br/&gt;    &lt;span style="color: green;"&gt;/*if(voltageLevel == 0x15)            //外部输入 打开对应功能口&lt;br/&gt;    {&lt;br/&gt;        P6SEL |= BIT7;                    //不需要，当用SVSIN时，自动从此脚检测&lt;br/&gt;    }*/&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue;"&gt;if&lt;/span&gt;(reset &amp;lt;= 1)&lt;br/&gt;    {&lt;br/&gt;        SVSCTL |= reset &amp;lt;&amp;lt; 3;&lt;br/&gt;    }&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;voltageLevel：这个参数和寄存器SVSCTL的高四位VLDx意思完全一样，程序仅仅是把它移动到高四位赋值给寄存器SVSCTL，reset参数对应PORON位，也是直接赋值给对应位完成设置。&lt;/p&gt;&lt;p&gt;检测是否有低于门限电压的情况出现：&lt;/p&gt;&lt;span style="color: blue;"&gt;char &lt;/span&gt;SvsFlg()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;return &lt;/span&gt;(SVSCTL&amp;amp;SVSFG);&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;这个函数更简单，仅仅把标志位SVSFG的值返回，以便用户判断是否出现了低于门限的情况出现。&lt;/p&gt;&lt;p&gt;标志位清零：&lt;/p&gt;&lt;span style="color: green;"&gt;/****************************************************************************&lt;br/&gt;* 名    称：ClearSvs&lt;br/&gt;* 功    能：电源电压监控器的过低标志&lt;br/&gt;* 入口参数：sync：同步 1：阻塞运行直到该函数电压恢复正常 0:不阻塞,清除即返回&lt;br/&gt;* 出口参数：无&lt;br/&gt;* 说    明: 若传入参数为0 不阻塞 则如果电压没有恢复到正常范围 则标志会立即被&lt;br/&gt;            单片机重新置位(1)&lt;br/&gt;****************************************************************************/&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;void &lt;/span&gt;ClearSvs(&lt;span style="color: blue;"&gt;char &lt;/span&gt;sync)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;if&lt;/span&gt;(!sync)&lt;br/&gt;    {&lt;br/&gt;        SVSCTL &amp;amp;=~ SVSFG;&lt;br/&gt;        &lt;span style="color: blue;"&gt;return&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: blue;"&gt;while&lt;/span&gt;(SVSCTL&amp;amp;SVSFG)&lt;br/&gt;        SVSCTL &amp;amp;=~ SVSFG;   &lt;span style="color: green;"&gt;//清除标志 直到电压正常&lt;br/&gt;&lt;/span&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;由于SVSFG标志位不会在处理后自动被清除，所以必须软件清零。这个函数有两种工作方式，同步阻塞等待，直到电压恢复正常后才返回和清零后即返回。&lt;/p&gt;&lt;p&gt;程序实现比较简单，但能够完成SVS的功能。下面介绍如何使用本程序库。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;使用示例：&lt;/strong&gt;&lt;p&gt;使用程序库的方式还是和以前一样：工程中加入SVS.c文件，源文件中加入对SVS.h的文件包含。&lt;/p&gt;&lt;p&gt;main.c主要内容如下：&lt;/p&gt;&lt;span style="color: blue;"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515;"&gt;&amp;lt;msp430x16x.h&amp;gt;   &lt;/span&gt;&lt;span style="color: green;"&gt;//430寄存器头文件&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515;"&gt;&amp;lt;stdio.h&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515;"&gt;"Lcd12864.h"&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515;"&gt;"SVS.h"&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: green;"&gt;/****************************************************************************&lt;br/&gt;* 名    称：main主程序&lt;br/&gt;* 功    能：设置串口，输出信息，从串口读计算机键盘输入数据，测试串口收发&lt;br/&gt;* 入口参数：无&lt;br/&gt;* 出口参数：无&lt;br/&gt;* 说    明：复位测试时 每次电压调低再调正常 液晶显示的数据加1&lt;br/&gt;            不复位时 每次调低 输出一个电压过低。&lt;br/&gt;****************************************************************************/&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;void &lt;/span&gt;main()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: green;"&gt;// Stop watchdog timer to prevent time out reset&lt;br/&gt;    &lt;/span&gt;WDTCTL = WDTPW + WDTHOLD;&lt;br/&gt;    ClkInit();&lt;br/&gt;    LcdInit();&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color: green;"&gt;/*//======== 电压过低时复位测试============&lt;br/&gt;    __no_init char ff;      //复位不初始化&lt;br/&gt;&lt;br/&gt;    SVSSetup(0x0A,1);       //检测电源电压 3.05v 低于3.05v时单片机复位&lt;br/&gt;    ff++;                   //此变量 每次复位加1&lt;br/&gt;    printf("%d",ff);        // 电压调低（&amp;lt;3.05v）再调高，显示变量将加1&lt;br/&gt;    */&lt;br/&gt;    &lt;/span&gt;SVSSetup(0x0A,0);       &lt;span style="color: green;"&gt;//测电源电压 3.05v 低于3.05v时单片机 不复位&lt;br/&gt;                            //0x0A 改为0x0f 则对P6.7电压监控 检测是否低于1.2v&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue;"&gt;while&lt;/span&gt;(1)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue;"&gt;if&lt;/span&gt;(SvsFlg()) &lt;br/&gt;            printf(&lt;span style="color: #a31515;"&gt;"电压过低"&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color: green;"&gt;//SVSFG位必须 软件清零，如果电压没有回到3.05以上，&lt;br/&gt;        //位的值立即被单片机置为1&lt;br/&gt;        &lt;/span&gt;ClearSvs(1);        &lt;span style="color: green;"&gt;//清除标志 直到恢复正常电压&lt;br/&gt;    &lt;/span&gt;}&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;本程序使用12864液晶来显示电压过低的情况：复位时，设置一个__no_init变量，每次复位加1，可以看到电压调低后，显示数字被加1.不复位置，显示电压过低。这里使用的是12864的底层驱动和printf函数移植，比之前做了稍微更改，这些在注释中说明的已经很详细了，这里不在细说。有关液晶和printf参考：&lt;a href="http://www.cnblogs.com/Engin/archive/2011/07/08/2100932.html"&gt;MSP430程序库&amp;lt;三&amp;gt;12864液晶程序库&lt;/a&gt;和&lt;a href="http://www.cnblogs.com/Engin/archive/2011/07/31/2122822.html"&gt;MSP430程序库&amp;lt;四&amp;gt;printf和scanf函数移植&lt;/a&gt;。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;SVS模块就到这里了，有什么不足，欢迎拍砖。&lt;/p&gt;&lt;p&gt;附件：&lt;a href="http://files.cnblogs.com/Engin/%E7%A8%8B%E5%BA%8F%E5%BA%93.rar"&gt;程序库&lt;/a&gt;&lt;/p&gt;&lt;p&gt;作者：&lt;b&gt;&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;给我一杯酒&lt;/a&gt;&lt;/b&gt;   &lt;br /&gt;出处：&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;http://Engin.cnblogs.com/&lt;/a&gt;   &lt;br /&gt;本文版权归作者和博客园共有，欢迎转载，转载保留此段文字并且注明出处；谢谢。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/Engin/aggbug/2156007.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/28/2156007.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Engin/archive/2011/08/27/2155680.html</id><title type="text">MSP430程序库&amp;lt;十一&amp;gt;定时器TA的PWM输出</title><summary type="text">定时器是单片机常用的其本设备，用来产生精确计时或是其他功能；msp430的定时器不仅可以完成精确定时，还能产生PWM波形输出，和捕获时刻值(上升沿或是下降沿到来的时候)。这里完成一个比较通用的P...</summary><published>2011-08-27T09:37:00Z</published><updated>2011-08-27T09:37:00Z</updated><author><name>给我一杯酒</name><uri>http://www.cnblogs.com/Engin/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Engin/archive/2011/08/27/2155680.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Engin/archive/2011/08/27/2155680.html"/><content type="html">&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;定时器是单片机常用的其本设备，用来产生精确计时或是其他功能；msp430的定时器不仅可以完成精确定时，还能产生PWM波形输出，和捕获时刻值(上升沿或是下降沿到来的时候)。这里完成一个比较通用的PWM波形产生程序。&lt;/p&gt; &lt;/blockquote&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;硬件介绍：&lt;/strong&gt;       &lt;p&gt;MSP430系列单片机的TimerA结构复杂，功能强大，适合应用于工业控制，如数字化电机控制，电表和手持式仪表的理想配置。它给开发人员提供了较多灵活的选择余地。当PWM 不需要修改占空比和时间时，TimerA 能自动输出PWM，而不需利用中断维持PWM输出。&lt;/p&gt;      &lt;p&gt;MSP430F16x和MSP430F14x单片机内部均含有两个定时器，TA和TB；TA有三个模块，CCR0-CCR2；TB含有CCR0-CCR67个模块；其中CCR0模块不能完整的输出PWM波形(只有三种输出模式可用);TA可以输出完整的2路PWM波形；TB可以输出6路完整的PWM波形。&lt;/p&gt;      &lt;p&gt;定时器的PWM输出有有8种模式：&lt;/p&gt;      &lt;p&gt;输出模式0&amp;#160; 输出模式：输出信号OUTx由每个捕获/比较模块的控制寄存器CCTLx中的OUTx位定义，并在写入该寄存器后立即更新。最终位OUTx直通。        &lt;br /&gt;输出模式1 置位模式：输出信号在TAR等于CCRx时置位，并保持置位到定时器复位或选择另一种输出模式为止。         &lt;br /&gt;输出模式2 PWM翻转/复位模式：输出在TAR的值等于CCRx时翻转，当TAR的值等于CCR0时复位。         &lt;br /&gt;输出模式3 PWM置位/复位模式：输出在TAR的值等于CCRx时置位，当TAR的值等于CCR0时复位。         &lt;br /&gt;输出模式4 翻转模式：输出电平在TAR的值等于CCRx时翻转，输出周期是定时器周期的2倍。         &lt;br /&gt;输出模式5复位模式：输出在TAR的值等于CCRx时复位，并保持低电平直到选择另一种输出模式。         &lt;br /&gt;输出模式6PWM翻转/置位模式：输出电平在TAR的值等于CCRx时翻转，当TAR值等于CCR0时置位。         &lt;br /&gt;输出模式7PWM复位/置位模式：输出电平在TAR的值等于CCRx时复位，当TAR的值等于CCR0时置位。 &lt;/p&gt;      &lt;p&gt;下图是增计数模式下的输出波形(本程序使用的是增模式3和7)： &lt;/p&gt;      &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108271735515507.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="375" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108271735561598.png" width="502" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;      &lt;p&gt;&lt;strong&gt;计数模式：&lt;/strong&gt;&lt;/p&gt;      &lt;p&gt;增计数模式        &lt;br /&gt;捕获/比较寄存器CCR0用作Timer_A增计数模式的周期寄存器，因为CCR0为16位寄存器，所以该模式适用于定时周期小于65 536的连续计数情况。计数器TAR可以增计数到CCR0的值，当计数值与CCR0的值相等(或定时器值大于CCR0的值)时，定时器复位并从0开始重新计数。 &lt;/p&gt;      &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108271735578991.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="92" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108271736038613.png" width="381" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;      &lt;p&gt;连续计数模式        &lt;br /&gt;在需要65 536个时钟周期的定时应用场合常用连续计数模式。定时器从当前值计数到0FFFFH后，又从0开始重新计数 &lt;/p&gt;      &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108271736041055.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="99" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108271736059004.png" width="378" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;      &lt;p&gt;增/减计数模式        &lt;br /&gt;需要对称波形的情况经常可以使用增/减计数模式，该模式下，定时器先增计数到CCR0的值，然后反向减计数到0。计数周期仍由CCR0定义，它是CCR0计数器数值的2倍。 &lt;/p&gt;      &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108271736055035.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="107" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108271736086689.png" width="380" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;      &lt;p&gt;TA定时器有比较、捕获两种工作方式；比较可以产生PWM波形等，捕获可以精确的测量时间；这里用的是比较输出。&lt;/p&gt;      &lt;p&gt;硬件介绍就这么多了，其他的可以参考msp430x1xx_family_users_guide(用户指南)。&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;程序实现：&lt;/strong&gt;       &lt;p&gt;本程序是直接从msp430f42x移植的，只改动了端口就能正常使用了。由此，430的模块在不同的系列中是通用的，有关寄存器是一样的；只是也许外部端口不太一样。&lt;/p&gt;      &lt;p&gt;程序初始化部分：完成TA相关寄存器的初始化。&lt;/p&gt;      &lt;span style="color: blue"&gt;char &lt;/span&gt;TAPwmInit(&lt;span style="color: blue"&gt;char &lt;/span&gt;Clk,&lt;span style="color: blue"&gt;char &lt;/span&gt;Div,&lt;span style="color: blue"&gt;char &lt;/span&gt;Mode1,&lt;span style="color: blue"&gt;char &lt;/span&gt;Mode2)&lt;br/&gt;{&lt;br/&gt;    TACTL = 0;                  &lt;span style="color: green"&gt;//清除以前设置&lt;br/&gt;    &lt;/span&gt;TACTL |= MC_1;              &lt;span style="color: green"&gt;//定时器TA设为增计数模式  &lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;switch&lt;/span&gt;(Clk)                 &lt;span style="color: green"&gt;//选择时钟源&lt;br/&gt;    &lt;/span&gt;{ &lt;br/&gt;        &lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'A'&lt;/span&gt;: &lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'a'&lt;/span&gt;:  TACTL|=TASSEL_1; &lt;span style="color: blue"&gt;break&lt;/span&gt;;    &lt;span style="color: green"&gt;//ACLK&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'S'&lt;/span&gt;: &lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'s'&lt;/span&gt;:  TACTL|=TASSEL_2; &lt;span style="color: blue"&gt;break&lt;/span&gt;;    &lt;span style="color: green"&gt;//SMCLK&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'E'&lt;/span&gt;:            TACTL|=TASSEL_0; &lt;span style="color: blue"&gt;break&lt;/span&gt;;    &lt;span style="color: green"&gt;//外部输入(TACLK)&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'e'&lt;/span&gt;:            TACTL|=TASSEL_3; &lt;span style="color: blue"&gt;break&lt;/span&gt;;    &lt;span style="color: green"&gt;//外部输入(TACLK取反)&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;default &lt;/span&gt;:  &lt;span style="color: blue"&gt;return&lt;/span&gt;(0);                           &lt;span style="color: green"&gt;//参数有误&lt;br/&gt;    &lt;/span&gt;} &lt;br/&gt;    &lt;span style="color: blue"&gt;switch&lt;/span&gt;(Div)                 &lt;span style="color: green"&gt;//选择分频系数&lt;br/&gt;    &lt;/span&gt;{ &lt;br/&gt;        &lt;span style="color: blue"&gt;case &lt;/span&gt;1:   TACTL|=ID_0; &lt;span style="color: blue"&gt;break&lt;/span&gt;;   &lt;span style="color: green"&gt;//1&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;case &lt;/span&gt;2:   TACTL|=ID_1; &lt;span style="color: blue"&gt;break&lt;/span&gt;;   &lt;span style="color: green"&gt;//2&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;case &lt;/span&gt;4:   TACTL|=ID_2; &lt;span style="color: blue"&gt;break&lt;/span&gt;;   &lt;span style="color: green"&gt;//4&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;case &lt;/span&gt;8:   TACTL|=ID_3; &lt;span style="color: blue"&gt;break&lt;/span&gt;;   &lt;span style="color: green"&gt;//8&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;default &lt;/span&gt;:  &lt;span style="color: blue"&gt;return&lt;/span&gt;(0);           &lt;span style="color: green"&gt;//参数有误&lt;br/&gt;    &lt;/span&gt;} &lt;br/&gt;    &lt;span style="color: blue"&gt;switch&lt;/span&gt;(Mode1)               &lt;span style="color: green"&gt;//设置PWM通道1的输出模式。&lt;br/&gt;    &lt;/span&gt;{ &lt;br/&gt;        &lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'P'&lt;/span&gt;:&lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'p'&lt;/span&gt;:          &lt;span style="color: green"&gt;//如果设置为高电平模式&lt;br/&gt;            &lt;/span&gt;TACCTL1 = OUTMOD_7;     &lt;span style="color: green"&gt;//高电平PWM输出&lt;br/&gt;            &lt;/span&gt;P1SEL |= BIT2;          &lt;span style="color: green"&gt;//从P1.2输出 (不同型号单片机可能不一样)&lt;br/&gt;            &lt;/span&gt;P1DIR |= BIT2;          &lt;span style="color: green"&gt;//从P1.2输出 (不同型号单片机可能不一样)              &lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue"&gt;break&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'N'&lt;/span&gt;:&lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'n'&lt;/span&gt;:          &lt;span style="color: green"&gt;//如果设置为低电平模式          &lt;br/&gt;            &lt;/span&gt;TACCTL1 = OUTMOD_3;     &lt;span style="color: green"&gt;//低电平PWM输出&lt;br/&gt;            &lt;/span&gt;P1SEL |= BIT2;          &lt;span style="color: green"&gt;//从P1.2输出 (不同型号单片机可能不一样) &lt;br/&gt;            &lt;/span&gt;P1DIR |= BIT2;          &lt;span style="color: green"&gt;//从P1.2输出 (不同型号单片机可能不一样)                &lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue"&gt;break&lt;/span&gt;; &lt;br/&gt;        &lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'0'&lt;/span&gt;:&lt;span style="color: blue"&gt;case &lt;/span&gt;0:            &lt;span style="color: green"&gt;//如果设置为禁用          &lt;br/&gt;            &lt;/span&gt;P1SEL &amp;amp;= ~BIT2;         &lt;span style="color: green"&gt;//P1.2恢复为普通IO口              &lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue"&gt;break&lt;/span&gt;;                 &lt;br/&gt;        &lt;span style="color: blue"&gt;default &lt;/span&gt;:  &lt;span style="color: blue"&gt;return&lt;/span&gt;(0);       &lt;span style="color: green"&gt;//参数有误&lt;br/&gt;    &lt;/span&gt;} &lt;br/&gt;    &lt;span style="color: blue"&gt;switch&lt;/span&gt;(Mode2)                   &lt;span style="color: green"&gt;//设置PWM通道1的输出模式。&lt;br/&gt;    &lt;/span&gt;{ &lt;br/&gt;        &lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'P'&lt;/span&gt;:&lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'p'&lt;/span&gt;:          &lt;span style="color: green"&gt;//如果设置为高电平模式&lt;br/&gt;            &lt;/span&gt;TACCTL2 =OUTMOD_7;      &lt;span style="color: green"&gt;//高电平PWM输出&lt;br/&gt;            &lt;/span&gt;P1SEL |= BIT3;          &lt;span style="color: green"&gt;//从P1.3输出 (不同型号单片机可能不一样)&lt;br/&gt;            &lt;/span&gt;P1DIR |= BIT3;          &lt;span style="color: green"&gt;//从P1.3输出 (不同型号单片机可能不一样)&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue"&gt;break&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'N'&lt;/span&gt;:&lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'n'&lt;/span&gt;:          &lt;span style="color: green"&gt;//如果设置为低电平模式          &lt;br/&gt;            &lt;/span&gt;TACCTL2 =OUTMOD_3;      &lt;span style="color: green"&gt;//低电平PWM输出&lt;br/&gt;            &lt;/span&gt;P1SEL |= BIT3;          &lt;span style="color: green"&gt;//从P1.3输出 (不同型号单片机可能不一样)  &lt;br/&gt;            &lt;/span&gt;P1DIR |= BIT3;          &lt;span style="color: green"&gt;//从P1.3输出 (不同型号单片机可能不一样)              &lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue"&gt;break&lt;/span&gt;; &lt;br/&gt;        &lt;span style="color: blue"&gt;case &lt;/span&gt;&lt;span style="color: #a31515"&gt;'0'&lt;/span&gt;:&lt;span style="color: blue"&gt;case &lt;/span&gt;0:            &lt;span style="color: green"&gt;//如果设置为禁用          &lt;br/&gt;            &lt;/span&gt;P1SEL &amp;amp;= ~BIT3;         &lt;span style="color: green"&gt;//P1.3恢复为普通IO口              &lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue"&gt;break&lt;/span&gt;;                 &lt;br/&gt;        &lt;span style="color: blue"&gt;default &lt;/span&gt;:  &lt;span style="color: blue"&gt;return&lt;/span&gt;(0);       &lt;span style="color: green"&gt;//参数有误&lt;br/&gt;    &lt;/span&gt;}    &lt;br/&gt;    &lt;span style="color: blue"&gt;return&lt;/span&gt;(1);  &lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;主要是设置TACTL寄存器，让TA工作于增模式，设置时钟源和分频；CCTLx设置对应的输出模式；并且打开相应端口的第二功能。&lt;/p&gt;    &lt;p&gt;设置周期函数：设置PWM波形的周期，单位是多少个TACLK周期。&lt;/p&gt;    &lt;span style="color: blue"&gt;void &lt;/span&gt;TAPwmSetPeriod(&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;Period)&lt;br/&gt;{&lt;br/&gt;    TACCR0 = Period;&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;工作于增模式时，TA计数到TACCR0,设CCR0就完成了周期的设置。&lt;/p&gt;    &lt;p&gt;设置占空比：设置TA的PWM输出的有效电平的时间。&lt;/p&gt;    &lt;span style="color: blue"&gt;void &lt;/span&gt;TAPwmSetDuty(&lt;span style="color: blue"&gt;char &lt;/span&gt;Channel,&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;Duty)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;switch&lt;/span&gt;(Channel)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue"&gt;case &lt;/span&gt;1: TACCR1=Duty; &lt;span style="color: blue"&gt;break&lt;/span&gt;; &lt;br/&gt;        &lt;span style="color: blue"&gt;case &lt;/span&gt;2: TACCR2=Duty; &lt;span style="color: blue"&gt;break&lt;/span&gt;;    &lt;br/&gt;    }&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;根据参数分别设置每一路的参数。&lt;/p&gt;    &lt;p&gt;设置占空比，用千分比设置：&lt;/p&gt;    &lt;span style="color: green"&gt;* 入口参数：Channel: 当前设置的通道号  1/2&lt;br/&gt;            Percent: PWM有效时间的千分比 (0~1000) &lt;br/&gt;* 出口参数：无&lt;br/&gt;* 说    明: 1000=100.0%  500=50.0% ，依次类推        &lt;br/&gt;* 范    例: TAPwmSetPermill(1,300)设置PWM通道1方波的占空比为30.0%&lt;br/&gt;            TAPwmSetPermill(2,825)设置PWM通道2方波的占空比为82.5%&lt;br/&gt;            */&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;TAPwmSetPermill(&lt;span style="color: blue"&gt;char &lt;/span&gt;Channel,&lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;Percent)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;unsigned long int &lt;/span&gt;Period;&lt;br/&gt;    &lt;span style="color: blue"&gt;unsigned int &lt;/span&gt;Duty;&lt;br/&gt;    Period = TACCR0;&lt;br/&gt;    Duty = Period * Percent / 1000;&lt;br/&gt;    TAPwmSetDuty(Channel,Duty);&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;这个函数用千分比来设置PWM输出的有效时间。方便程序的使用。&lt;/p&gt;    &lt;p&gt;有关定时器，TI提供的大量的例程，这些历程都很简洁、清晰。需要其他功能可以自己根据例程编写对应的程序。程序实现就这么多了，下面说下本程序的使用方法。&lt;/p&gt;  &lt;/li&gt;  &lt;li&gt;&lt;strong&gt;使用示例：&lt;/strong&gt;     &lt;p&gt;使用方式：依然是在工程中加入c文件；文件包含h头文件；然后就可以正常使用本函数了。详细参考示例工程和main.c。&lt;/p&gt;    &lt;p&gt;main主要程序如下：&lt;/p&gt;    &lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;msp430x16x.h&amp;quot;     &lt;/span&gt;&lt;span style="color: green"&gt;//430寄存器头文件&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;TAPwm.h&amp;quot;          &lt;/span&gt;&lt;span style="color: green"&gt;//TA PWM输出程序库头文件&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;main()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: green"&gt;// Stop watchdog timer to prevent time out reset&lt;br/&gt;    &lt;/span&gt;WDTCTL = WDTPW + WDTHOLD;&lt;br/&gt;    ClkInit();&lt;br/&gt;    &lt;br/&gt;    TAPwmInit(&lt;span style="color: #a31515"&gt;'A'&lt;/span&gt;,1,&lt;span style="color: #a31515"&gt;'P'&lt;/span&gt;,&lt;span style="color: #a31515"&gt;'P'&lt;/span&gt;);   &lt;span style="color: green"&gt;//将定时器TA初始化成为PWM发生器&lt;br/&gt;                  //时钟源=ACLK ; 无分频;  通道1和通道2均设为高电平模式。&lt;br/&gt;    &lt;/span&gt;TAPwmSetPeriod(500);        &lt;span style="color: green"&gt;//通道1/2的PWM方波周期均设为500个时钟周期&lt;br/&gt;    &lt;/span&gt;TAPwmSetDuty(1,200);        &lt;span style="color: green"&gt;//1通道 有效200个时钟周期&lt;br/&gt;    &lt;/span&gt;TAPwmSetPermill(2,200);     &lt;span style="color: green"&gt;//2通道 20.0%&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;LPM0;&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;本程序调用程序库，产生两路PWM波形。&lt;/p&gt;  &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;TA的PWM输出就到这儿了，如果需要更多路的PWM波，可以使用TB，他可以产生6路完整的PWM波形；可以参考本程序编写TB的波形输出程序。有什么不足之处，欢迎评论，讨论。&lt;/p&gt;&lt;p&gt;附件：&lt;a href="http://files.cnblogs.com/Engin/%E7%A8%8B%E5%BA%8F%E5%BA%93.rar"&gt;程序库&lt;/a&gt;&lt;/p&gt;&lt;p&gt;作者：&lt;b&gt;&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;给我一杯酒&lt;/a&gt;&lt;/b&gt;   &lt;br /&gt;出处：&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;http://Engin.cnblogs.com/&lt;/a&gt;   &lt;br /&gt;本文版权归作者和博客园共有，欢迎转载，转载保留此段文字并且注明出处；谢谢。 &lt;/p&gt;&lt;img src="http://www.cnblogs.com/Engin/aggbug/2155680.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/27/2155680.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Engin/archive/2011/08/26/2154677.html</id><title type="text">MSP430程序库&amp;lt;十&amp;gt;ADC12模块</title><summary type="text">msp430内部含有ADC12模块，可以完成12位的模数转换，当对精度或其他指标要求不高时，可以选用430单片机内部的ADC12完成模数转换工作。这里主要实现了一个比较通用的ADC12模块初始化...</summary><published>2011-08-26T07:38:00Z</published><updated>2011-08-26T07:38:00Z</updated><author><name>给我一杯酒</name><uri>http://www.cnblogs.com/Engin/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Engin/archive/2011/08/26/2154677.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Engin/archive/2011/08/26/2154677.html"/><content type="html">&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;msp430内部含有ADC12模块，可以完成12位的模数转换，当对精度或其他指标要求不高时，可以选用430单片机内部的ADC12完成模数转换工作。这里主要实现了一个比较通用的ADC12模块初始化程序，具体的数据存储和处理需要自己在中断处理函数中添加。&lt;/p&gt; &lt;/blockquote&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;硬件介绍：&lt;/strong&gt;       &lt;p&gt;msp430单片机内的ADC12模块的特点如下：&lt;font face="Fixedsys"&gt;12位转换精度，1位非线形误差，1位非线形积分误差；多种时钟源给ADC12模块，切本身自带时钟发生器；内置温度传感器；TimerA/TimerB硬件触发器；8路外部通道和4路内部通道；内置参考电压源和6种参考电压组合；4种模式的模数转换；16bit的转换缓存；ADC12关闭支持超低功耗；采用速度快，最高200Kbps；自动扫描和DMA使能。&lt;/font&gt;430内部的ADC12功能还是蛮强大的，可以有定时器触发模数转换开始，还可以和内部的DMA模块共同使用，完成高速的采样转储等高级功能。&lt;/p&gt;      &lt;p&gt;这个AD的转化公式如下，可以根据它计算采样的模拟电压值：&lt;/p&gt;      &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;       &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108261535012614.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="65" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108261535046188.png" width="270" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;     &lt;/blockquote&gt;      &lt;p&gt;使用AD是还要注意采样时间，430单片机的模数ADC12模块的等效模拟电压输入电路如下： &lt;/p&gt;      &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108261535061006.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="137" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108261535117413.png" width="489" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;      &lt;p&gt;其中V&lt;sub&gt;S&lt;/sub&gt;是信号源电压，R&lt;sub&gt;S&lt;/sub&gt;是信号源内阻，V&lt;sub&gt;I&lt;/sub&gt;在Ax(ADC12模块模拟输入端)上的电压，R&lt;sub&gt;I&lt;/sub&gt;单片机内多路开关等效电阻，V&lt;sub&gt;C&lt;/sub&gt;是保持电容上的电压(ADC12模块采样的电压)，C&lt;sub&gt;I &lt;/sub&gt;是电容的值。需要根据这些值计算采样时间：&lt;/p&gt;      &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/20110826153521534.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="54" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108261535228799.png" width="360" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;      &lt;p&gt;代入单片机上的参数后公式如下：&lt;/p&gt;      &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108261535225352.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="49" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108261537104484.png" width="364" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;      &lt;p&gt;我的程序中采样时间设的是4us，可以算出如果用我的程序(不更改采样时间)的话，最大信号源内阻可以是6.8k，当信号源内阻更大时，可以自己按要求设采样时间(在程序的初始化函数内的寄存器设置部分)。&lt;/p&gt;      &lt;p&gt;还有，ADC模数转换时要求参考电压等很稳定，为了达到这个要求，德州仪器要求这部分的电路如下：&lt;/p&gt;      &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108261537313352.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="441" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108261537462356.png" width="460" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;      &lt;p&gt;即：所有参考源和电源均并联一组 0.1uF和10uF的电容。&lt;/p&gt;      &lt;p&gt;硬件部分就说这么多了；如果需要更详细的说明，参考用户指南。&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;程序实现：&lt;/strong&gt;       &lt;p&gt;程序主要实现的是一个比较通用的初始化程序，内容如下：&lt;/p&gt;      &lt;span style="color: blue"&gt;char &lt;/span&gt;ADC12Init(&lt;span style="color: blue"&gt;char &lt;/span&gt;n,&lt;span style="color: blue"&gt;char &lt;/span&gt;channels[],&lt;span style="color: blue"&gt;char &lt;/span&gt;rep)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;if&lt;/span&gt;(n&amp;gt;15)&lt;br/&gt;        &lt;span style="color: blue"&gt;return &lt;/span&gt;0;&lt;br/&gt;    &lt;span style="color: green"&gt;//SHT0_0 &lt;br/&gt;    &lt;/span&gt;ADC12CTL0 = ADC12ON + MSC + SHT0_0 + REFON + REF2_5V;&lt;span style="color: green"&gt;// 开启ad,参考电压2.5v&lt;br/&gt;    &lt;/span&gt;ADC12CTL1 = SHP + ADC12SSEL_3;                  &lt;span style="color: green"&gt;//Use sampling timer, SMCLK&lt;br/&gt;    &lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;for&lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;i = 0;i &amp;lt; n;i++)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue"&gt;if&lt;/span&gt;(channels[i] &amp;gt;= 0x80)&lt;br/&gt;            &lt;span style="color: blue"&gt;return &lt;/span&gt;0;&lt;br/&gt;        *(&lt;span style="color: blue"&gt;char&lt;/span&gt;*)(ADC12MCTL0_ + i) = channels[i];    &lt;span style="color: green"&gt;//每个MCTL设置&lt;br/&gt;    &lt;/span&gt;}&lt;br/&gt;    *(&lt;span style="color: blue"&gt;char&lt;/span&gt;*)(ADC12MCTL0_ + n - 1) |= EOS;           &lt;span style="color: green"&gt;//序列结束&lt;br/&gt;    &lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt;(rep != 0)                                  &lt;span style="color: green"&gt;//多次转换&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        ADC12CTL1 |= CONSEQ_3;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: blue"&gt;else&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        ADC12CTL1 |= CONSEQ_1;&lt;br/&gt;    }&lt;br/&gt;    &lt;br/&gt;    ADC12IE = 1&amp;lt;&amp;lt;(n-1);                                 &lt;span style="color: green"&gt;// Enable ADC12IFG.n-1&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;return &lt;/span&gt;1;&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;程序先判断n 通道总数是否超过了可用的个数，超过则返回零然后设置ADC12CTL0和ADC12CTL1中不需要特殊设置的部分，然后在设置通道模式(根据rep参数的值)；for循环设置的是每个存储寄存器的设置ADC12MCTLx ；*(&lt;span style="color: blue"&gt;char&lt;/span&gt;*)(ADC12MCTL0_ + n - 1) |= EOS; &lt;span style="color: green"&gt;//序列结束 &lt;/span&gt;这句加入序列结束标志；最后设置中断寄存器并返回成功设置标志。其中比较特殊的是ADC12MCTL0_，这个是430提供的头文件中定义的ADC12MCTL0的地址值，以其为指针首址操作ADCMCTLx寄存器，从而利用循环设置寄存器的内容，大量减少了代码行数。&lt;/p&gt;    &lt;p&gt;参数channels[]是每个存储寄存器的设置(除EOS位之外的)，含义如下：&lt;/p&gt;    &lt;span style="color: green"&gt;channels[]:对应通道设置，高四位，参考源选择；&lt;br/&gt;低四位，通道选择。具体如下：&lt;br/&gt;SREFx Bits&lt;br/&gt;6-4&lt;br/&gt;Select reference&lt;br/&gt;000 VR+ = AVCC and VR. = AVSS&lt;br/&gt;001 VR+ = VREF+ and VR. = AVSS&lt;br/&gt;010 VR+ = VeREF+ and VR. = AVSS&lt;br/&gt;011 VR+ = VeREF+ and VR. = AVSS&lt;br/&gt;100 VR+ = AVCC and VR. = VREF./ VeREF.&lt;br/&gt;101 VR+ = VREF+ and VR. = VREF./ VeREF.&lt;br/&gt;110 VR+ = VeREF+ and VR. = VREF./ VeREF.&lt;br/&gt;111 VR+ = VeREF+ and VR. = VREF./ VeREF.&lt;br/&gt;INCHx Bits&lt;br/&gt;3-0&lt;br/&gt;Input channel select&lt;br/&gt;0000 A0&lt;br/&gt;0001 A1&lt;br/&gt;0010 A2&lt;br/&gt;0011 A3&lt;br/&gt;0100 A4&lt;br/&gt;0101 A5&lt;br/&gt;0110 A6&lt;br/&gt;0111 A7&lt;br/&gt;1000 VeREF+&lt;br/&gt;1001 VREF./VeREF.&lt;br/&gt;1010 Temperature sensor&lt;br/&gt;1011 (AVCC – AVSS) / 2&lt;br/&gt;1100 (AVCC – AVSS) / 2&lt;br/&gt;1101 (AVCC – AVSS) / 2&lt;br/&gt;1110 (AVCC – AVSS) / 2&lt;br/&gt;1111 (AVCC – AVSS) / 2&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;这是从用户指南里复制来的，每一位和ADC12MCTLx的意义相同(去掉EOS位)，所以可用宏定义来制定这个参数，如：&lt;/p&gt;    &lt;span style="color: blue"&gt;char &lt;/span&gt;channels[3];&lt;br/&gt;channels[0] = SREF_1+INCH_0;&lt;br/&gt;channels[1] = SREF_1+INCH_1;&lt;br/&gt;channels[2] = SREF_1+INCH_2;&lt;br/&gt;ADC12Init(3,channels,1);    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;这是3个通道A0-A2采样，多次采样。&lt;/p&gt;    &lt;p&gt;启动转换函数：&lt;/p&gt;    &lt;span style="color: blue"&gt;void &lt;/span&gt;ADC12Start()&lt;br/&gt;{&lt;br/&gt;    ADC12CTL0 |= ENC;&lt;br/&gt;    ADC12CTL0 |= ADC12SC;&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;ADC初始化完成后，调用此函数开始AD转换，转换完成后(一个序列通道，如：刚才的0-2)，程序自动进入AD中断，用户需要在这里为自己的函数添加处理逻辑；这里只存储了转化的结果：&lt;/p&gt;    &lt;span style="color: blue"&gt;#pragma &lt;/span&gt;vector=ADC_VECTOR&lt;br/&gt;__interrupt &lt;span style="color: blue"&gt;void &lt;/span&gt;ADC12ISR (&lt;span style="color: blue"&gt;void&lt;/span&gt;)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;static int &lt;/span&gt;i;&lt;br/&gt;    results[0][i] = ADC12MEM0;                &lt;span style="color: green"&gt;// Move results, IFG is cleared&lt;br/&gt;    &lt;/span&gt;results[1][i] = ADC12MEM1;                &lt;span style="color: green"&gt;// Move results, IFG is cleared&lt;br/&gt;    &lt;/span&gt;results[2][i] = ADC12MEM2;                &lt;span style="color: green"&gt;// Move results, IFG is cleared&lt;br/&gt;    &lt;/span&gt;i++;&lt;br/&gt;    &lt;span style="color: blue"&gt;if&lt;/span&gt;(i&amp;gt;31)                                  &lt;span style="color: green"&gt;//多次转换时 转换次数&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color: green"&gt;//多次重复采样时，在这里方处理函数&lt;br/&gt;        &lt;/span&gt;ADC12CTL0 &amp;amp;=~ ENC;                      &lt;span style="color: green"&gt;//停止转换&lt;br/&gt;        &lt;/span&gt;i=0;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;该程序实现的是多次A0-A2 32次转换，把结果存入results数组。单次时，仅仅采样一次(A0-A2)可用自己更改处理函数。&lt;/p&gt;    &lt;p&gt;程序部分就完成了，调用时注意要自己实现处理逻辑或存储逻辑。&lt;/p&gt;  &lt;/li&gt;  &lt;li&gt;&lt;strong&gt;使用示例：&lt;/strong&gt; &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;本程序使用方式还是加入C文件，包含H文件；不过和之前的程序不同的是要自己实现中断处理逻辑。&lt;/p&gt;&lt;p&gt;使用示例参见程序库中的ADC12.&lt;/p&gt;&lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;lt;msp430x16x.h&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;ADC12.h&amp;quot;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;main( &lt;span style="color: blue"&gt;void &lt;/span&gt;)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: green"&gt;// Stop watchdog timer to prevent time out reset&lt;br/&gt;    &lt;/span&gt;WDTCTL = WDTPW + WDTHOLD;&lt;br/&gt;    ClkInit();&lt;br/&gt;    &lt;span style="color: blue"&gt;char &lt;/span&gt;channels[3];&lt;br/&gt;    channels[0] = SREF_1+INCH_0;&lt;br/&gt;    channels[1] = SREF_1+INCH_1;&lt;br/&gt;    channels[2] = SREF_1+INCH_2;&lt;br/&gt;    ADC12Init(3,channels,1);&lt;br/&gt;    _EINT();&lt;br/&gt;    ADC12Start();&lt;br/&gt;    LPM0;&lt;br/&gt;}&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;这里实现的是3通道多次转换，参考电压都是内部参考电压。自己实现的处理逻辑参见前面的程序实现的最后一部分。&lt;/p&gt;&lt;p&gt;ADC12模块部分就到这里了，有什么不足之处，欢迎提出建议、讨论。&lt;/p&gt;&lt;p&gt;附件：&lt;a href="http://files.cnblogs.com/Engin/%E7%A8%8B%E5%BA%8F%E5%BA%93.rar"&gt;程序库&lt;/a&gt;&lt;/p&gt;&lt;p&gt;作者：&lt;b&gt;&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;给我一杯酒&lt;/a&gt;&lt;/b&gt;   &lt;br /&gt;出处：&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;http://Engin.cnblogs.com/&lt;/a&gt;   &lt;br /&gt;本文版权归作者和博客园共有，欢迎转载，转载保留此段文字并且注明出处；谢谢。 &lt;/p&gt;&lt;img src="http://www.cnblogs.com/Engin/aggbug/2154677.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/26/2154677.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Engin/archive/2011/08/23/2151130.html</id><title type="text">MSP430程序库&amp;lt;九&amp;gt;数码管显示</title><summary type="text">数码管也是单片机系统最常用的输出设备之一(还有液晶、发光二极管等)。七段(这里用的是8段，有小数点)数码管可以完成显示0-9数字和一部分的英文字符如：A、b。本文实现的程序完成显示数字和可显示的英文字符；同时完成数码管显示的printf函数的移植...</summary><published>2011-08-23T10:48:00Z</published><updated>2011-08-23T10:48:00Z</updated><author><name>给我一杯酒</name><uri>http://www.cnblogs.com/Engin/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Engin/archive/2011/08/23/2151130.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Engin/archive/2011/08/23/2151130.html"/><content type="html">&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;数码管也是单片机系统最常用的输出设备之一(还有液晶、发光二极管等)。七段(这里用的是8段，有小数点)数码管可以完成显示0-9数字和一部分的英文字符如：A、b。本文实现的程序完成显示数字和可显示的英文字符；同时完成数码管显示的printf函数的移植，以支持printf的格式化字符等好用的特点（我用的数码管8个排为一排，方便数字等的显示）。&lt;/p&gt;&lt;/blockquote&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;硬件介绍：&lt;/strong&gt;&lt;p&gt;这里所用到的硬件资源包括8个数码管、和msp430单片机的两个8位IO口(这里用的是P3和P5口，如有改变，可以通过宏定义更改)。&lt;/p&gt;&lt;p&gt;数码管是8个共阴的数码管，a-h 8段通过一个200&amp;Omega;的电阻接到430单片机的P5口。共阴端是由单片机的P3口控制，单片机的一位IO通过一个三极管接到数码管的共阴端，以完成位选。&lt;/p&gt;&lt;p&gt;单片机的P3口时数码管的位选口，某位为高则选中；P5口时段选口；要数码管显示时，通过P3位选，选中某个数码管亮，P5段选选择8段（a-h）中的那些亮，从而控制某一位显示数字或字符。&lt;/p&gt;&lt;p&gt;要同时显示多个数码管，就要动态扫描；动态扫描时，本程序选用的是由看门狗的中断扫描显示：每1.9ms显示其中的一位，动态扫描显示每一位，从而让数码管看起来是同时亮的。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;程序实现：&lt;/strong&gt;&lt;p&gt;数码管显示首先要有一个数码管显示的断码表（完成数字和字符到数码管段值的表），程序中采用了《MSP430系列单片机系统工程设计与实践》这本书推荐的方式实现的这个数码表：先用宏定义定义每段对应的单片机要输出的段值，然后再实现是个表，当硬件改变时，只需更改前面的每段的段值定义即可，改动的地方少了很多，代码如下：&lt;/p&gt;&lt;span style="color: green;"&gt;/*宏定义，数码管a-h各段对应的比特，更换硬件只用改动以下8行*/&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;a       0x01                            &lt;span style="color: green;"&gt;//  AAAA&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;b       0x02                            &lt;span style="color: green;"&gt;// F    B&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;c       0x04                            &lt;span style="color: green;"&gt;// F    B&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;d       0x08                            &lt;span style="color: green;"&gt;//  GGGG&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;e       0x10                            &lt;span style="color: green;"&gt;// E    C&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;f       0x20                            &lt;span style="color: green;"&gt;// E    C&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;g       0x40                            &lt;span style="color: green;"&gt;//  DDDD  HH&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;h       0x80        &lt;span style="color: green;"&gt;//小数点&lt;br/&gt;&lt;br/&gt;/*用宏定义自动生成段码表，很好的写法，值得学习*/&lt;br/&gt;/*更换硬件无需重写段码表*/&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;const char &lt;/span&gt;Tab[] = {&lt;br/&gt;    a + b + c + d + e + f,                  &lt;span style="color: green;"&gt;// Displays "0"&lt;br/&gt;    &lt;/span&gt;b + c,                                  &lt;span style="color: green;"&gt;// Displays "1"&lt;br/&gt;    &lt;/span&gt;a + b + d + e + g,                      &lt;span style="color: green;"&gt;// Displays "2"&lt;br/&gt;    &lt;/span&gt;a + b + c + d + g,                      &lt;span style="color: green;"&gt;// Displays "3"&lt;br/&gt;    &lt;/span&gt;b + c + f + g,                          &lt;span style="color: green;"&gt;// Displays "4"&lt;br/&gt;    &lt;/span&gt;a + c + d + f +g,                       &lt;span style="color: green;"&gt;// Displays "5"&lt;br/&gt;    &lt;/span&gt;a + c + d + e + f + g,                  &lt;span style="color: green;"&gt;// Displays "6"&lt;br/&gt;    &lt;/span&gt;a + b + c,                              &lt;span style="color: green;"&gt;// Displays "7"&lt;br/&gt;    &lt;/span&gt;a + b + c + d + e + f + g,              &lt;span style="color: green;"&gt;// Displays "8"&lt;br/&gt;    &lt;/span&gt;a + b + c + d + f + g,                  &lt;span style="color: green;"&gt;// Displays "9"&lt;br/&gt;    &lt;/span&gt;a + b + c + e + f + g,                  &lt;span style="color: green;"&gt;// Displays "A"&lt;br/&gt;    &lt;/span&gt;c + d + e + f + g,                      &lt;span style="color: green;"&gt;// Displays "B"  &lt;br/&gt;    &lt;/span&gt;a + d + e + f,                          &lt;span style="color: green;"&gt;// Displays "C"&lt;br/&gt;    &lt;/span&gt;b + c + d + e + g,                      &lt;span style="color: green;"&gt;// Displays "D"&lt;br/&gt;    &lt;/span&gt;a + d + e + f + g,                      &lt;span style="color: green;"&gt;// Displays "E"&lt;br/&gt;    &lt;/span&gt;a + e + f + g,                          &lt;span style="color: green;"&gt;// Displays "F"&lt;br/&gt;    &lt;/span&gt;a + c + d + e + f,                      &lt;span style="color: green;"&gt;// Displays "G"&lt;br/&gt;    &lt;/span&gt;b + c + e + f + g,                      &lt;span style="color: green;"&gt;// Displays "H"  &lt;br/&gt;    &lt;/span&gt;e + f,                                  &lt;span style="color: green;"&gt;// Displays "I"&lt;br/&gt;    &lt;/span&gt;b + c + d + e,                          &lt;span style="color: green;"&gt;// Displays "J"&lt;br/&gt;    &lt;/span&gt;b + d + e + f + g,                      &lt;span style="color: green;"&gt;// Displays "K"&lt;br/&gt;    &lt;/span&gt;d + e + f,                              &lt;span style="color: green;"&gt;// Displays "L"  &lt;br/&gt;    &lt;/span&gt;a + c + e + g,                          &lt;span style="color: green;"&gt;// Displays "M" &lt;br/&gt;    &lt;/span&gt;a + b + c + e + f,                      &lt;span style="color: green;"&gt;// Displays "N"   &lt;br/&gt;    &lt;/span&gt;c + e + g,                              &lt;span style="color: green;"&gt;// Displays "n"&lt;br/&gt;    &lt;/span&gt;c + d + e + g,                          &lt;span style="color: green;"&gt;// Displays "o"&lt;br/&gt;    &lt;/span&gt;a + b + c + d + e + f,                  &lt;span style="color: green;"&gt;// Displays "O"&lt;br/&gt;    &lt;/span&gt;a + b + e + f + g,                      &lt;span style="color: green;"&gt;// Displays "P"&lt;br/&gt;    &lt;/span&gt;a + b + c + f + g,                      &lt;span style="color: green;"&gt;// Displays "Q" &lt;br/&gt;    &lt;/span&gt;e + g,                                  &lt;span style="color: green;"&gt;// Displays "r"&lt;br/&gt;    &lt;/span&gt;a + c + d + f +g,                       &lt;span style="color: green;"&gt;// Displays "S"&lt;br/&gt;    &lt;/span&gt;d + e + f + g,                          &lt;span style="color: green;"&gt;// Displays "t"&lt;br/&gt;    &lt;/span&gt;a + e + f ,                             &lt;span style="color: green;"&gt;// Displays "T" &lt;br/&gt;    &lt;/span&gt;b + c + d + e + f,                      &lt;span style="color: green;"&gt;// Displays "U"&lt;br/&gt;    &lt;/span&gt;c + d + e,                              &lt;span style="color: green;"&gt;// Displays "v" &lt;br/&gt;    &lt;/span&gt;b + d + f + g,                          &lt;span style="color: green;"&gt;// Displays "W"&lt;br/&gt;    &lt;/span&gt;b + c + d + f + g,                      &lt;span style="color: green;"&gt;// Displays "Y" &lt;br/&gt;    &lt;/span&gt;a + b + d + e + g,                      &lt;span style="color: green;"&gt;// Displays "Z"&lt;br/&gt;    &lt;/span&gt;g,                                      &lt;span style="color: green;"&gt;// Displays "-"&lt;br/&gt;    &lt;/span&gt;h,                                      &lt;span style="color: green;"&gt;// Displays "."  &lt;br/&gt;    &lt;/span&gt;0                                       &lt;span style="color: green;"&gt;// Displays " "&lt;br/&gt;&lt;/span&gt;}; &lt;br/&gt;&lt;span style="color: blue;"&gt;#undef &lt;/span&gt;a&lt;br/&gt;&lt;span style="color: blue;"&gt;#undef &lt;/span&gt;b&lt;br/&gt;&lt;span style="color: blue;"&gt;#undef &lt;/span&gt;c&lt;br/&gt;&lt;span style="color: blue;"&gt;#undef &lt;/span&gt;d&lt;br/&gt;&lt;span style="color: blue;"&gt;#undef &lt;/span&gt;e&lt;br/&gt;&lt;span style="color: blue;"&gt;#undef &lt;/span&gt;f&lt;br/&gt;&lt;span style="color: blue;"&gt;#undef &lt;/span&gt;g     &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;0-9的位置对应显示0-9，之后的是A开始往后显示，为了方便访问这个表格，定义了AA等一系列的常量，方便访问这个表。&lt;/p&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;AA  10&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;BB  AA+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;CC  BB+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;DD  CC+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;EE  DD+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;FF  EE+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;GG  FF+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;HH  GG+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;II  HH+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;JJ  II+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;KK  JJ+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;LL  KK+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;mm  LL+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;NN  mm+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;nn  NN+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;oo  nn+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;OO  oo+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;PP  OO+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;QQ  PP+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;rr  QQ+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;SS  rr+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;tt  SS+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;TT  tt+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;UU  TT+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;VV  UU+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;WW  VV+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;YY  WW+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;ZZ  YY+1&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;NEG ZZ+1    &lt;span style="color: green;"&gt;/*   -  */  //负号&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;DOT NEG+1   &lt;span style="color: green;"&gt;/*   .  */  //小数点&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;SP  DOT+1   &lt;span style="color: green;"&gt;/* 空白 */  //空格&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;A从10开始访问这个表格，如果要显示A只需这样用Tab[AA]，即可得到需要的段值，AA-空格的宏定义放在H文件里，方便其他文件访问（当要调用显示函数的时候需要AA等宏定义）。为什么是AA而不是A呢？主要原因是单字母的有几个已经在单片机430的头文件里定义了，为了访问的时候一致，就都用两个字母的了。&lt;/p&gt;&lt;p&gt;为了动态扫描，这里定义了一个全局数组(数码管的程序可以访问)Nixie[8]在这个里面的8个char对应8个数码管要显示的段值。初始值是8个数码管都不显示：&lt;/p&gt;&lt;span style="color: blue;"&gt;char &lt;/span&gt;Nixie[8] = &lt;span style="color: #a31515;"&gt;"\0\0\0\0\0\0\0\0"&lt;/span&gt;;     &lt;span style="color: green;"&gt;//初始状态 不显示&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;动态扫描时，函数每1.9ms(设的看门狗定时中断)调用一次显示函数，每次显示一位(为了让中断占用更少的时间，这样中断里只需赋值即可)。函数如下：&lt;/p&gt;&lt;span style="color: blue;"&gt;void &lt;/span&gt;Display()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;static char &lt;/span&gt;i = 0;      &lt;span style="color: green;"&gt;//记录扫描显示到哪位&lt;br/&gt;    &lt;/span&gt;CTRL_OUT = 1&amp;lt;&amp;lt;i;&lt;br/&gt;    DATA_OUT = Nixie[i];&lt;br/&gt;    i++;&lt;br/&gt;    &lt;span style="color: blue;"&gt;if&lt;/span&gt;(i&amp;gt;7)&lt;br/&gt;        i = 0;&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;这个函数供中断调用，i用来保存要显示哪一位。CTRL_OUT 、DATA_OUT 是宏定义的位选和段选口。中断程序如下：&lt;/p&gt;&lt;span style="color: blue;"&gt;#pragma &lt;/span&gt;vector=WDT_VECTOR&lt;br/&gt;__interrupt &lt;span style="color: blue;"&gt;void &lt;/span&gt;WDT_ISR()&lt;br/&gt;{&lt;br/&gt;    Display();&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;中断只调用了一个函数，这样很方便换其他中断来定时。&lt;/p&gt;&lt;p&gt;中断是必须初始设置的，还有IO口，要设为输出方向 ，初始化函数完成数码管用到的单片机资源的初始工作：&lt;/p&gt;&lt;span style="color: blue;"&gt;void &lt;/span&gt;NixiettubeInit()&lt;br/&gt;{&lt;br/&gt;    WDTCTL = WDT_ADLY_1_9;  &lt;span style="color: green;"&gt;//看门狗内部定时器模式16ms&lt;br/&gt;    &lt;/span&gt;IE1 |= WDTIE;           &lt;span style="color: green;"&gt;//允许看门狗中断&lt;br/&gt;    &lt;/span&gt;CTRL_DIR_OUT;&lt;br/&gt;    DATA_DIR_OUT;&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;首先，设置中断并允许中断；然后设置位选和段选所用的端口为输出方向。CTRL_DIR_OUT; DATA_DIR_OUT; 和刚才用到的两个OUT的宏定义如下：&lt;/p&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;DATA_DIR_OUT    P5DIR|=0XFF&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;CTRL_DIR_OUT    P3DIR|=0XFF&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;DATA_OUT        P5OUT&lt;br/&gt;&lt;span style="color: blue;"&gt;#define &lt;/span&gt;CTRL_OUT        P3OUT    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;这样处理之后，要显示数字就很简单了:只需把要显示的数字或字符的段码值放入Nixie[8]数组对应的位置即可，如显示韩输入下：&lt;/p&gt;&lt;span style="color: blue;"&gt;void &lt;/span&gt;NixiettubeDisplayChar(&lt;span style="color: blue;"&gt;char &lt;/span&gt;ch,&lt;span style="color: blue;"&gt;char &lt;/span&gt;addr)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;if&lt;/span&gt;(ch == DOT)       &lt;span style="color: green;"&gt;//小数点,不需单独占一位&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        Nixie[addr] |= Tab[ch];&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: blue;"&gt;else&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        Nixie[addr] = Tab[ch];&lt;br/&gt;    }&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;如果是小数点，放入对应位置的h段即可，其他直接覆盖。&lt;/p&gt;&lt;p&gt;插入字符函数：在最右端插入数字或字符.&lt;/p&gt;&lt;span style="color: blue;"&gt;void &lt;/span&gt;NixiettubeInsertChar(&lt;span style="color: blue;"&gt;char &lt;/span&gt;ch)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;if&lt;/span&gt;(ch == DOT)       &lt;span style="color: green;"&gt;////小数点,不需单独占一位&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        Nixie[0] |= Tab[ch];&lt;br/&gt;        &lt;span style="color: blue;"&gt;return&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: blue;"&gt;for&lt;/span&gt;(&lt;span style="color: blue;"&gt;int &lt;/span&gt;i = 7;i &amp;gt; 0;i--)&lt;br/&gt;        Nixie[i] = Nixie[i - 1];     &lt;span style="color: green;"&gt;//已显示字符左移一位&lt;br/&gt;    &lt;/span&gt;Nixie[0] = Tab[ch];&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;这个也是先判断小数点，小数点直接放到h段，其他的，则要已显示的左移再覆盖最右一位，源程序的注释很详细，可具体才、可以下载附件的程序库。&lt;/p&gt;&lt;p&gt;数码管清除函数，这个函数把数码管全部显示去掉，即把缓存数组内每项都置为0：&lt;/p&gt;&lt;span style="color: blue;"&gt;void &lt;/span&gt;NixiettubeClear()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;for&lt;/span&gt;(&lt;span style="color: blue;"&gt;int &lt;/span&gt;i = 0;i &amp;lt; 8;i++)&lt;br/&gt;        Nixie[i] = Tab[SP];     &lt;span style="color: green;"&gt;//显示空格&lt;br/&gt;&lt;/span&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;程序比较简单，这里就不多解释了。&lt;/p&gt;&lt;p&gt;数码管的程序就这么多了，所有函数都列出来了。下面开始介绍printf的移植，具体过程不再详细说了，详细过程参考：&lt;a href="http://www.cnblogs.com/Engin/archive/2011/07/31/2122822.html"&gt;MSP430程序库&amp;lt;四&amp;gt;printf和scanf函数移植&lt;/a&gt;。这里主要介绍所需程序。&lt;/p&gt;&lt;p&gt;单片机printf使用需要用户提供底层驱动-putchar函数，printf完成格式化等一系列活动后调用putchar输出字符流。只要实现putchar，包含stdio.h文件，就可以使用printf函数。移植的数码管的putchar函数如下：&lt;/p&gt;&lt;span style="color: blue;"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515;"&gt;&amp;lt;stdio.h&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515;"&gt;"ctype.h"       &lt;/span&gt;&lt;span style="color: green;"&gt;/*isdigit函数需要该头文件*/&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515;"&gt;"Nixietube.h"&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;int &lt;/span&gt;putchar(&lt;span style="color: blue;"&gt;int &lt;/span&gt;ch)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: green;"&gt;//'\f'表示走纸翻页，相当于清除显示&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue;"&gt;if&lt;/span&gt;(ch==&lt;span style="color: #a31515;"&gt;'\n'&lt;/span&gt;||ch==&lt;span style="color: #a31515;"&gt;'\r'&lt;/span&gt;)&lt;br/&gt;        NixiettubeClear();&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color: green;"&gt;//数字和对应ASCII字母之间差0x30   '1'=0x31 '2'=0x32... &lt;br/&gt;    //isdigit也是C语言标准函数&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue;"&gt;if&lt;/span&gt;(isdigit(ch))&lt;br/&gt;        NixiettubeInsertChar(ch-0x30);  &lt;span style="color: green;"&gt;//若字符是数字则显示数字&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue;"&gt;else             &lt;/span&gt;&lt;span style="color: green;"&gt;//否则，不是数字，是字母&lt;br/&gt;        &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color: blue;"&gt;switch&lt;/span&gt;(ch)    &lt;span style="color: green;"&gt;//根据字母选择程序分支&lt;br/&gt;        &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'A'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'a'&lt;/span&gt;: NixiettubeInsertChar(AA);&lt;span style="color: blue;"&gt;break&lt;/span&gt;; &lt;span style="color: green;"&gt;//字符A&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'B'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'b'&lt;/span&gt;: NixiettubeInsertChar(BB);&lt;span style="color: blue;"&gt;break&lt;/span&gt;; &lt;span style="color: green;"&gt;//字符B&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'C'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'c'&lt;/span&gt;: NixiettubeInsertChar(CC);&lt;span style="color: blue;"&gt;break&lt;/span&gt;; &lt;span style="color: green;"&gt;//...&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'D'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'d'&lt;/span&gt;: NixiettubeInsertChar(DD);&lt;span style="color: blue;"&gt;break&lt;/span&gt;;  &lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'E'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'e'&lt;/span&gt;: NixiettubeInsertChar(EE);&lt;span style="color: blue;"&gt;break&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'F'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'f'&lt;/span&gt;: NixiettubeInsertChar(FF);&lt;span style="color: blue;"&gt;break&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'G'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'g'&lt;/span&gt;: NixiettubeInsertChar(GG);&lt;span style="color: blue;"&gt;break&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'H'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'h'&lt;/span&gt;: NixiettubeInsertChar(HH);&lt;span style="color: blue;"&gt;break&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'I'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'i'&lt;/span&gt;: NixiettubeInsertChar(II);&lt;span style="color: blue;"&gt;break&lt;/span&gt;; &lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'J'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'j'&lt;/span&gt;: NixiettubeInsertChar(JJ);&lt;span style="color: blue;"&gt;break&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'K'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'k'&lt;/span&gt;: NixiettubeInsertChar(KK);&lt;span style="color: blue;"&gt;break&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'L'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'l'&lt;/span&gt;: NixiettubeInsertChar(LL);&lt;span style="color: blue;"&gt;break&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'M'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'m'&lt;/span&gt;: NixiettubeInsertChar(mm);&lt;span style="color: blue;"&gt;break&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'N'&lt;/span&gt;:           NixiettubeInsertChar(NN);&lt;span style="color: blue;"&gt;break&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'n'&lt;/span&gt;:           NixiettubeInsertChar(nn);&lt;span style="color: blue;"&gt;break&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'O'&lt;/span&gt;:           NixiettubeInsertChar(OO);&lt;span style="color: blue;"&gt;break&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'o'&lt;/span&gt;:           NixiettubeInsertChar(oo);&lt;span style="color: blue;"&gt;break&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'P'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'p'&lt;/span&gt;: NixiettubeInsertChar(PP);&lt;span style="color: blue;"&gt;break&lt;/span&gt;; &lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'Q'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'q'&lt;/span&gt;: NixiettubeInsertChar(QQ);&lt;span style="color: blue;"&gt;break&lt;/span&gt;; &lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'R'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'r'&lt;/span&gt;: NixiettubeInsertChar(rr);&lt;span style="color: blue;"&gt;break&lt;/span&gt;; &lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'S'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'s'&lt;/span&gt;: NixiettubeInsertChar(SS);&lt;span style="color: blue;"&gt;break&lt;/span&gt;; &lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'T'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'t'&lt;/span&gt;: NixiettubeInsertChar(tt);&lt;span style="color: blue;"&gt;break&lt;/span&gt;; &lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'U'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'v'&lt;/span&gt;: NixiettubeInsertChar(UU);&lt;span style="color: blue;"&gt;break&lt;/span&gt;; &lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'V'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'u'&lt;/span&gt;: NixiettubeInsertChar(VV);&lt;span style="color: blue;"&gt;break&lt;/span&gt;; &lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'W'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'w'&lt;/span&gt;: NixiettubeInsertChar(WW);&lt;span style="color: blue;"&gt;break&lt;/span&gt;; &lt;br/&gt;            &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'Y'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'y'&lt;/span&gt;: NixiettubeInsertChar(YY);&lt;span style="color: blue;"&gt;break&lt;/span&gt;; &lt;span style="color: green;"&gt;//...&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'Z'&lt;/span&gt;: &lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'z'&lt;/span&gt;: NixiettubeInsertChar(ZZ);&lt;span style="color: blue;"&gt;break&lt;/span&gt;; &lt;span style="color: green;"&gt;//字符Z&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'-'&lt;/span&gt;:           NixiettubeInsertChar(NEG);&lt;span style="color: blue;"&gt;break&lt;/span&gt;;&lt;span style="color: green;"&gt;//字符-&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'.'&lt;/span&gt;:           NixiettubeInsertChar(DOT);&lt;span style="color: blue;"&gt;break&lt;/span&gt;;&lt;span style="color: green;"&gt;//小数点，直接显示在右下角&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue;"&gt;case &lt;/span&gt;&lt;span style="color: #a31515;"&gt;' '&lt;/span&gt;:           NixiettubeInsertChar(SP);&lt;span style="color: blue;"&gt;break&lt;/span&gt;; &lt;span style="color: green;"&gt;//空格&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue;"&gt;default &lt;/span&gt;:           NixiettubeInsertChar(SP);&lt;span style="color: blue;"&gt;break&lt;/span&gt;;&lt;span style="color: green;"&gt;//显示不出来的字母用空格替代&lt;br/&gt;        &lt;/span&gt;} &lt;br/&gt;    } &lt;br/&gt;    &lt;span style="color: blue;"&gt;return&lt;/span&gt;(ch);  &lt;span style="color: green;"&gt;//返回显示的字符(putchar函数标准格式要求返回显示字符)&lt;br/&gt;&lt;/span&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;头文件必须包含stdio.h，这样告诉编译器printf调用时，用这里的putchar函数。然后判断字符，分类进行显示，不能显示的空一格。&lt;/p&gt;&lt;p&gt;数码管的程序就完成了，如果需要可以自己添加改写函数，如：当和键盘共同使用时，如果键盘移植了scanf函数，并且支持退格；可以改写函数-让数码管的putchar支持退格操作。或者用的是我的键盘程序，需要10多ms调用一次键盘处理函数，这样可以和这个数码管扫描公用一个中断：&lt;/p&gt;&lt;span style="color: blue;"&gt;void &lt;/span&gt;Display()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;static char &lt;/span&gt;i = 0;      &lt;span style="color: green;"&gt;//记录扫描显示到哪位&lt;br/&gt;    &lt;/span&gt;CTRL_OUT = 1&amp;lt;&amp;lt;i;&lt;br/&gt;    DATA_OUT = Nixie[i];&lt;br/&gt;    i++;&lt;br/&gt;    &lt;span style="color: blue;"&gt;if&lt;/span&gt;(i&amp;gt;7)&lt;br/&gt;    {&lt;br/&gt;        i = 0;&lt;br/&gt;        KeyProcess();&lt;br/&gt;    }&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;这样改写，然后把键盘的中断去掉(别忘了key.h包含和加入KeyProcess(); 的声明；如果程序中有两个指向同一个中断时，会编译错误)；这样就可以键盘、和数码管共同使用了。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;使用示例&lt;/strong&gt;：&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;使用方法还是和之前一样，工程中加入Nixietube.c文件，然后在要调用的地方加入Nixietube.h的包含；如puchr函数，和示例工程的main.c&lt;/p&gt;&lt;p&gt;main.c调用的方式如下：&lt;/p&gt;&lt;span style="color: blue;"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515;"&gt;&amp;lt;msp430x16x.h&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515;"&gt;&amp;lt;stdio.h&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515;"&gt;"Nixietube.h"&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;void &lt;/span&gt;ClkInit()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;char &lt;/span&gt;i;&lt;br/&gt;    BCSCTL1 &amp;amp;= ~XT2OFF;             &lt;span style="color: green;"&gt;//打开XT2振荡器&lt;br/&gt;    &lt;/span&gt;IFG1&amp;amp;=~OFIFG;                   &lt;span style="color: green;"&gt;//清除振荡错误标志&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue;"&gt;while&lt;/span&gt;((IFG1&amp;amp;OFIFG)!=0)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue;"&gt;for&lt;/span&gt;(i=0;i&amp;lt;0xff;i++);&lt;br/&gt;        IFG1&amp;amp;=~OFIFG;               &lt;span style="color: green;"&gt;//清除振荡错误标志&lt;br/&gt;    &lt;/span&gt;}&lt;br/&gt;    BCSCTL2 |= SELM_2+SELS+DIVS_3;  &lt;span style="color: green;"&gt;//MCLK为8MHz，SMCLK为1MHz&lt;br/&gt;&lt;/span&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color: blue;"&gt;void &lt;/span&gt;main( &lt;span style="color: blue;"&gt;void &lt;/span&gt;)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: green;"&gt;// Stop watchdog timer to prevent time out reset&lt;br/&gt;    &lt;/span&gt;WDTCTL = WDTPW + WDTHOLD;&lt;br/&gt;    ClkInit();&lt;br/&gt;    NixiettubeInit();&lt;br/&gt;    _EINT();&lt;br/&gt;    &lt;span style="color: green;"&gt;//while(1)&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        NixiettubeDisplayChar(AA,5);&lt;br/&gt;        NixiettubeDisplayChar(DOT,5);&lt;br/&gt;        NixiettubeInsertChar(2);&lt;br/&gt;        NixiettubeInsertChar(DOT);&lt;br/&gt;        NixiettubeInsertChar(2);&lt;br/&gt;        printf(&lt;span style="color: #a31515;"&gt;"%1.2f"&lt;/span&gt;,1.2);&lt;br/&gt;    }&lt;br/&gt;}&lt;p&gt;&lt;/p&gt;&lt;p&gt;包含msp430的头文件，以便使用430单片机的先关资源；加入stdio.h以使用printf函数；加入Nixietube.h使用数码管的相关程序。&lt;/p&gt;&lt;p&gt;还要注意，为了数码管正常显示，必须打开总中断，以使数码管动态扫描显示。另外，本程序单步调试看不到数码管正常显示，因为没有扫描。只有全速运行才可以看到数码管的显示情况。&lt;/p&gt;&lt;p&gt;数码管的程序就到这里，不足之处，欢迎讨论提出建议。&lt;/p&gt;&lt;p&gt;附件：&lt;a href="http://files.cnblogs.com/Engin/%E7%A8%8B%E5%BA%8F%E5%BA%93.rar"&gt;程序库&lt;/a&gt;&lt;/p&gt;&lt;p&gt;作者：&lt;b&gt;&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;给我一杯酒&lt;/a&gt;&lt;/b&gt;   &lt;br /&gt;出处：&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;http://Engin.cnblogs.com/&lt;/a&gt;   &lt;br /&gt;本文版权归作者和博客园共有，欢迎转载，转载保留此段文字并且注明出处；谢谢。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/Engin/aggbug/2151130.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/23/2151130.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Engin/archive/2011/08/22/2149448.html</id><title type="text">MSP430程序库&amp;lt;八&amp;gt;DAC12的使用</title><summary type="text">MSP430 带有的DAC12 模块，可以将运算处理的结果转换为模拟量，以便操作被控制对象的工作过程。DA是在控制操作过程中常用的器件之一；MSP430有些系列中含有DAC12模块，给需要使用DA的方案提供了许多方便。这里实现较为简单的DAC的驱动，方便以后使用。</summary><published>2011-08-22T07:18:00Z</published><updated>2011-08-22T07:18:00Z</updated><author><name>给我一杯酒</name><uri>http://www.cnblogs.com/Engin/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Engin/archive/2011/08/22/2149448.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Engin/archive/2011/08/22/2149448.html"/><content type="html">&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;MSP430 带有的DAC12 模块，可以将运算处理的结果转换为模拟量，以便操作被控制对象的工作过程。DA是在控制操作过程中常用的器件之一；MSP430有些系列中含有DAC12模块，给需要使用DA的方案提供了许多方便。这里实现较为简单的DAC的驱动，方便以后使用。&lt;/p&gt;&lt;/blockquote&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;硬件介绍：&lt;/strong&gt;&lt;p&gt;MSP430x14x系列不含DAC12模块，所以本文的实现只能用于16系列等含有DAC12模块的单片机中。&lt;/p&gt;&lt;p&gt;MSP430F169 单片机的DAC12 模块有2 个DAC 通道，这两个通道在操作上是完全平等的。并且可以用DAC12GRP控制位将多个DAC12通道组合起来，实现同步更新，硬件还能确保同步更新独立于任何中断或者NMI事件。&lt;/p&gt;&lt;p&gt;这个DAC12模块有以下特点：8位或12位分辨率可调、可编程时间对能量的损耗、可选内部或外部参考源、支持二进制原码和补码输入、具有自校验功能、可以多路DAC同步更新、还可以用DMA等。&lt;/p&gt;&lt;p&gt;这里实现的是较为简化的版本，需要可以自己添加或改写功能，如：初始化函数内部调用自校验的函数，可以在每一次初始化时候均自校验。&lt;/p&gt;&lt;p&gt;DAC12每个模块只有两个寄存器：控制寄存和数据寄存器，控制寄存器用来初始化和设置模块的使用，数据寄存器用来存放要输出的电压数字量。169的DAC的寄存器如下：        &lt;br /&gt;DAC12_0控制寄存器&amp;nbsp;&amp;nbsp;&amp;nbsp; DAC12_0CTL         &lt;br /&gt;DAC12_0数据寄存器&amp;nbsp;&amp;nbsp;&amp;nbsp; DAC12_0DAT         &lt;br /&gt;DAC12_1控制寄存器&amp;nbsp;&amp;nbsp;&amp;nbsp; DAC12_1CTL         &lt;br /&gt;DAC12_1数据寄存器&amp;nbsp;&amp;nbsp;&amp;nbsp; DAC12_1DAT&lt;/p&gt;&lt;p&gt;控制寄存器每一位的功能如下：&lt;/p&gt;&lt;p&gt;DAC12REFx：选择DAC12的参考源        &lt;br /&gt;0，1 Vref+         &lt;br /&gt;2，3 Veref+         &lt;br /&gt;DAC12RES：选择DAC12分辨率         &lt;br /&gt;0 12位分辨率         &lt;br /&gt;1 8分辨率         &lt;br /&gt;DAC12LSELx：锁存器触发源选择         &lt;br /&gt;当 DAC12锁存器得到触发之后，能够将锁存器中的数据传送到DAC12的内核。         &lt;br /&gt;当 DAC12LSELx=0的时候，DAC数据更新不受DAC12ENC 的影响。         &lt;br /&gt;0 DAC12_XDAT执行写操作将触发（不考虑DAC12ENC 的状态）         &lt;br /&gt;1 DAC12_XDAT执行写操作将触发（考虑DAC12ENC 的状态）         &lt;br /&gt;2 Timer_A3.OUT1的上升沿         &lt;br /&gt;3 Timer_B7.OUT2的上升沿         &lt;br /&gt;DAC12CALON：DAC12校验操作控制         &lt;br /&gt;置位后启动校验操作，校验完成后自动被复位。校验操作可以校正偏移误差。         &lt;br /&gt;0 没有启动校验操作         &lt;br /&gt;1 启动校验操作         &lt;br /&gt;DAC12IR：DAC12输入范围         &lt;br /&gt;设定输入参考电压和输出的关系         &lt;br /&gt;0 DAC12的满量程为参考电压的3倍（不操作AVcc）         &lt;br /&gt;1 DAC12的满量程为参考电压         &lt;br /&gt;DAC12AMPx：DAC12运算放大器设置         &lt;br /&gt;0 输入缓冲器关闭，输出缓冲器关闭，高阻         &lt;br /&gt;1 输入缓冲器关闭，输出缓冲器关闭，0V         &lt;br /&gt;2 输入缓冲器低速低电流，输出缓冲器低速低电流         &lt;br /&gt;3 输入缓冲器低速低电流，输出缓冲器中速中电流         &lt;br /&gt;4 输入缓冲器低速低电流，输出缓冲器高速高电流         &lt;br /&gt;5 输入缓冲器中速中电流，输出缓冲器中速中电流         &lt;br /&gt;6 输入缓冲器中速中电流，输出缓冲器高速高电流         &lt;br /&gt;7 输入缓冲器高速高电流，输出缓冲器高速高电流         &lt;br /&gt;DAC12DF：DAC12的数据格式         &lt;br /&gt;0 二进制         &lt;br /&gt;1 二进制补码         &lt;br /&gt;DAC12IE：DAC12的中断允许         &lt;br /&gt;0 禁止中断         &lt;br /&gt;1 允许中断         &lt;br /&gt;DAC12IFG：DAC12的中断标志位         &lt;br /&gt;0 没有中断请求         &lt;br /&gt;1 有中断请求         &lt;br /&gt;DAC12ENC：DAC12转换控制位         &lt;br /&gt;DAC12LSEL&amp;gt;0的时候，DAC12ENC 才有效。         &lt;br /&gt;0 DAC12停止         &lt;br /&gt;1 DAC12转换         &lt;br /&gt;DAC12GRP：DAC12组合控制位         &lt;br /&gt;0 没有组合         &lt;br /&gt;1 组合&lt;/p&gt;&lt;p&gt;详细的有关DAC12的资料可以参考TI提供的用户指南。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;程序实现：&lt;/strong&gt;&lt;p&gt;DAC12模块的程序比较简单，因为每组只有一个寄存器用来控制；本程序实现的功能如下：DAC模块初始化，完成两个DAC模块的初始化，可以根据参数判断要是、初始化的是哪个模块或两个都初始化，或是两个一组同时更新；用参数传递DAC12AMPx的值，方便设置，程序中注释很详细，如果不理解，可以直接设AMPx为5或0x05；校准函数，完成DAC12模块的自校准，也是通过参数传递要校准的模块；电压输出函数，同样这个也是用参数传递要输出的模块。&lt;/p&gt;&lt;p&gt;初始化：&lt;/p&gt;&lt;span style="color: green;"&gt;/********************************************************&lt;br/&gt;* 函数名称：DAC12Init&lt;br/&gt;* 功    能：DAC12用到的相关资源初始化&lt;br/&gt;* 参    数：&lt;br/&gt;*           module模块  0:使用模块DAC12_0&lt;br/&gt;*                       1:使用模块DAC12_1&lt;br/&gt;*                       2:使用模块DAC12_0/1&lt;br/&gt;*                       3:使用模块DAC12_0/1 共同更新&lt;br/&gt;*           DAC12AMPx：DAC运算放大器设置：&lt;br/&gt;*               0 输入缓冲器关闭，输出缓冲器关闭，高阻&lt;br/&gt;*               1 输入缓冲器关闭，输出缓冲器关闭，0V&lt;br/&gt;*               2 输入缓冲器低速/电流，输出缓冲器低速/电流&lt;br/&gt;*               3 输入缓冲器低速/电流，输出缓冲器中速/电流&lt;br/&gt;*               4 输入缓冲器低速/电流，输出缓冲器高速/电流&lt;br/&gt;*               5 输入缓冲器中速/电流，输出缓冲器中速/电流&lt;br/&gt;*               6 输入缓冲器中速/电流，输出缓冲器高速/电流&lt;br/&gt;*               7 输入缓冲器高速/电流，输出缓冲器高速/电流&lt;br/&gt;* 返 回 值：char，设置成功返回1，参数错误返回0&lt;br/&gt;* 说    明：其他默认为：12位方案、写入即更新输出，module模&lt;br/&gt;*           块为3时，两个都写入更新；DAC12的满量程为参考电&lt;br/&gt;*           压；内部2.5v参考电压：需要AD设置参考源打开2.5.&lt;br/&gt;*********************************************************/&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;char &lt;/span&gt;DAC12Init(&lt;span style="color: blue;"&gt;char &lt;/span&gt;module,&lt;span style="color: blue;"&gt;char &lt;/span&gt;DAC12AMPx)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;if&lt;/span&gt;(DAC12AMPx&amp;gt;7)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue;"&gt;return&lt;/span&gt;(0);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: green;"&gt;//---------------------------设置模块-------------------------------  &lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue;"&gt;switch&lt;/span&gt;(module)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue;"&gt;case &lt;/span&gt;0:&lt;span style="color: blue;"&gt;case&lt;/span&gt;&lt;span style="color: #a31515;"&gt;'0'&lt;/span&gt;: DAC12_0Init(DAC12AMPx); &lt;span style="color: blue;"&gt;break&lt;/span&gt;;  &lt;span style="color: green;"&gt;//模块0&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue;"&gt;case &lt;/span&gt;1:&lt;span style="color: blue;"&gt;case&lt;/span&gt;&lt;span style="color: #a31515;"&gt;'1'&lt;/span&gt;: DAC12_1Init(DAC12AMPx); &lt;span style="color: blue;"&gt;break&lt;/span&gt;;  &lt;span style="color: green;"&gt;//模块1&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue;"&gt;case &lt;/span&gt;2:&lt;span style="color: blue;"&gt;case&lt;/span&gt;&lt;span style="color: #a31515;"&gt;'2'&lt;/span&gt;: &lt;br/&gt;            DAC12_0Init(DAC12AMPx);&lt;br/&gt;            DAC12_1Init(DAC12AMPx);&lt;br/&gt;            &lt;span style="color: blue;"&gt;break&lt;/span&gt;;                                      &lt;span style="color: green;"&gt;//模块0、1  &lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue;"&gt;case &lt;/span&gt;3:&lt;span style="color: blue;"&gt;case&lt;/span&gt;&lt;span style="color: #a31515;"&gt;'3'&lt;/span&gt;:&lt;br/&gt;            DAC12_0Init(DAC12AMPx);&lt;br/&gt;            DAC12_1Init(DAC12AMPx);&lt;br/&gt;            DAC12_0CTL |= DAC12GRP;&lt;br/&gt;            &lt;span style="color: blue;"&gt;break&lt;/span&gt;;  &lt;span style="color: green;"&gt;//无校验&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue;"&gt;default &lt;/span&gt;:         &lt;span style="color: blue;"&gt;return&lt;/span&gt;(0);                            &lt;span style="color: green;"&gt;//参数错误&lt;br/&gt;    &lt;/span&gt;}&lt;br/&gt;    &lt;span style="color: blue;"&gt;return &lt;/span&gt;(1);&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;这里参数无效返回0，设置完成返回1，不过要注意的是在使用DAC之前，必须开启内部参考源（在ADC模块里面，具体可以参考使用示例）。&lt;/p&gt;&lt;p&gt;DAC12_0Init和DAC12_1Init函数内容一样，只不过控制寄存器分别是DAC12_0CTL和DAC12_0CTL，这里只给出DAC12_0Init的函数，另一个参考源程序：&lt;/p&gt;&lt;span style="color: blue;"&gt;void &lt;/span&gt;DAC12_0Init(&lt;span style="color: blue;"&gt;char &lt;/span&gt;DAC12AMPx)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: green;"&gt;// Internal ref gain 1&lt;br/&gt;    &lt;/span&gt;DAC12_0CTL = DAC12SREF_0 + DAC12IR;&lt;br/&gt;    DAC12_0CTL |= DAC12LSEL_1 + (DAC12AMPx &amp;lt;&amp;lt; 5);&lt;br/&gt;    DAC12_0CTL |= DAC12ENC;&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;这个函数仅仅完成控制寄存器的设置。选内部参考源，输出满量程是参考电压的1倍，更新方式：写入即更新，如果group设置，则两个都写入才更新。&lt;/p&gt;&lt;p&gt;校准函数：完成DAC12模块自校准，&lt;/p&gt;&lt;span style="color: blue;"&gt;void &lt;/span&gt;DAC12Cal(&lt;span style="color: blue;"&gt;char &lt;/span&gt;module)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;switch&lt;/span&gt;(module)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue;"&gt;case &lt;/span&gt;0:&lt;span style="color: blue;"&gt;case&lt;/span&gt;&lt;span style="color: #a31515;"&gt;'0'&lt;/span&gt;: &lt;br/&gt;            DAC12_0CTL |= DAC12CALON;               &lt;span style="color: green;"&gt;// 启动效验DAC&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue;"&gt;while&lt;/span&gt;((DAC12_0CTL &amp;amp; DAC12CALON) != 0);  &lt;span style="color: green;"&gt;// 等待效验完成&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue;"&gt;break&lt;/span&gt;;                                  &lt;span style="color: green;"&gt;//模块0&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue;"&gt;case &lt;/span&gt;1:&lt;span style="color: blue;"&gt;case&lt;/span&gt;&lt;span style="color: #a31515;"&gt;'1'&lt;/span&gt;: &lt;br/&gt;            DAC12_1CTL |= DAC12CALON;               &lt;span style="color: green;"&gt;// 启动效验DAC&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue;"&gt;while&lt;/span&gt;((DAC12_1CTL &amp;amp; DAC12CALON) != 0);  &lt;span style="color: green;"&gt;// 等待效验完成&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue;"&gt;break&lt;/span&gt;;                                  &lt;span style="color: green;"&gt;//模块1&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue;"&gt;case &lt;/span&gt;2:&lt;span style="color: blue;"&gt;case&lt;/span&gt;&lt;span style="color: #a31515;"&gt;'2'&lt;/span&gt;:&lt;br/&gt;        &lt;span style="color: blue;"&gt;case &lt;/span&gt;3:&lt;span style="color: blue;"&gt;case&lt;/span&gt;&lt;span style="color: #a31515;"&gt;'3'&lt;/span&gt;: &lt;br/&gt;            DAC12_0CTL |= DAC12CALON;               &lt;span style="color: green;"&gt;// 启动效验DAC&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue;"&gt;while&lt;/span&gt;((DAC12_0CTL &amp;amp; DAC12CALON) != 0);  &lt;span style="color: green;"&gt;// 等待效验完成&lt;br/&gt;            &lt;/span&gt;DAC12_1CTL |= DAC12CALON;               &lt;span style="color: green;"&gt;// 启动效验DAC&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue;"&gt;while&lt;/span&gt;((DAC12_1CTL &amp;amp; DAC12CALON) != 0);  &lt;span style="color: green;"&gt;// 等待效验完成&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue;"&gt;break&lt;/span&gt;;                                  &lt;span style="color: green;"&gt;//模块0、1  &lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue;"&gt;default &lt;/span&gt;:       &lt;span style="color: blue;"&gt;return&lt;/span&gt;;                     &lt;span style="color: green;"&gt;//参数错误&lt;br/&gt;    &lt;/span&gt;}&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;参数含义和前初始化的函数相同，为了使用函数时一致。&lt;/p&gt;&lt;p&gt;输出函数：&lt;/p&gt;&lt;span style="color: blue;"&gt;void &lt;/span&gt;DAC12Out(&lt;span style="color: blue;"&gt;char &lt;/span&gt;module,&lt;span style="color: blue;"&gt;int &lt;/span&gt;out)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;switch&lt;/span&gt;(module)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue;"&gt;case &lt;/span&gt;0:&lt;span style="color: blue;"&gt;case&lt;/span&gt;&lt;span style="color: #a31515;"&gt;'0'&lt;/span&gt;: DAC12_0DAT=out; &lt;span style="color: blue;"&gt;break&lt;/span&gt;;      &lt;span style="color: green;"&gt;//模块0&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue;"&gt;case &lt;/span&gt;1:&lt;span style="color: blue;"&gt;case&lt;/span&gt;&lt;span style="color: #a31515;"&gt;'1'&lt;/span&gt;: DAC12_1DAT=out; &lt;span style="color: blue;"&gt;break&lt;/span&gt;;      &lt;span style="color: green;"&gt;//模块1&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue;"&gt;case &lt;/span&gt;2:&lt;span style="color: blue;"&gt;case&lt;/span&gt;&lt;span style="color: #a31515;"&gt;'2'&lt;/span&gt;:&lt;br/&gt;        &lt;span style="color: blue;"&gt;case &lt;/span&gt;3:&lt;span style="color: blue;"&gt;case&lt;/span&gt;&lt;span style="color: #a31515;"&gt;'3'&lt;/span&gt;: DAC12_0DAT=out; DAC12_1DAT=out; &lt;span style="color: blue;"&gt;break&lt;/span&gt;;  &lt;span style="color: green;"&gt;//模块0、1  &lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue;"&gt;default &lt;/span&gt;:       &lt;span style="color: blue;"&gt;return&lt;/span&gt;;                                 &lt;span style="color: green;"&gt;//参数错误&lt;br/&gt;    &lt;/span&gt;}&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;输出函数的参数也和初始化的module参数含义相同，这个函数比较简单，只是按照要输出的值赋给DAT寄存器。&lt;/p&gt;&lt;p&gt;DAC12的程序库就这么多，DAC12还可以严格按时间更新数据，以输出一定频率的波形，可以设置为TA out1上升沿更新数据，或TB out2上升沿更新。另外还可以和DMA共同使用，完成更复杂的功能；这里均没有实现，需要的话可以根据寄存器功能来实现。&lt;/p&gt;&lt;p&gt;程序部分就到这了。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;使用示例：&lt;/strong&gt;&lt;p&gt;这里的使用方式依然和之前的程序一样，加入C文件，包含H文件即可，另外，使用本程序，必须开启内部AD参考源，为DAC12模块提供参考电压。&lt;/p&gt;&lt;span style="color: blue;"&gt;void &lt;/span&gt;main( &lt;span style="color: blue;"&gt;void &lt;/span&gt;)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: green;"&gt;// Stop watchdog timer to prevent time out reset&lt;br/&gt;    &lt;/span&gt;WDTCTL = WDTPW + WDTHOLD;&lt;br/&gt;    ClkInit();&lt;br/&gt;    DAC12Init(3,5);                 &lt;span style="color: green;"&gt;//初始化&lt;br/&gt;    &lt;/span&gt;DAC12Cal(2);                    &lt;span style="color: green;"&gt;//校准&lt;br/&gt;    &lt;/span&gt;ADC12CTL0 = REF2_5V + REFON;    &lt;span style="color: green;"&gt;//开启内部参考源 2.5v 必须有；以供DA使用&lt;br/&gt;    &lt;/span&gt;DAC12Out(2,0x666);&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;p&gt;ADC12CTL0 = REF2_5V + REFON;这句即是开启参考电压2.5v以供DA使用。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;DAC12模块的程序库就到这里了，有什么不对的地方欢迎拍砖。&lt;/p&gt;&lt;p&gt;附件：&lt;a href="http://files.cnblogs.com/Engin/%E7%A8%8B%E5%BA%8F%E5%BA%93.rar"&gt;程序库&lt;/a&gt;&lt;/p&gt;&lt;p&gt;作者：&lt;b&gt;&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;给我一杯酒&lt;/a&gt;&lt;/b&gt;   &lt;br /&gt;出处：&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;http://Engin.cnblogs.com/&lt;/a&gt;   &lt;br /&gt;本文版权归作者和博客园共有，欢迎转载，转载保留此段文字并且注明出处；谢谢。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/Engin/aggbug/2149448.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/22/2149448.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Engin/archive/2011/08/21/2147724.html</id><title type="text">MSP430程序库&amp;lt;七&amp;gt;按键</title><summary type="text">按键是单片机系统最常用的输入设备之一；几乎是只要需要交互输入，就必须有键盘。这篇博客实现了一个通用的键盘程序，只要提供一个读取键值的函数(底层键值)，程序将完成消抖、存入队列等一些列处理。同时本程序提供最常用的4*4矩阵键盘的程序，和4个按键的程序。 硬件介绍： 本文主要实现了一个键盘的通用框架，可以很方便的改为不同的键盘函数，这里实现了两种按键4个单独按键和4*4行列...</summary><published>2011-08-21T03:31:00Z</published><updated>2011-08-21T03:31:00Z</updated><author><name>给我一杯酒</name><uri>http://www.cnblogs.com/Engin/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Engin/archive/2011/08/21/2147724.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Engin/archive/2011/08/21/2147724.html"/><content type="html">&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;按键是单片机系统最常用的输入设备之一；几乎是只要需要交互输入，就必须有键盘。这篇博客实现了一个通用的键盘程序，只要提供一个读取键值的函数(底层键值)，程序将完成消抖、存入队列等一些列处理。同时本程序提供最常用的4*4矩阵键盘的程序，和4个按键的程序。&lt;/p&gt; &lt;/blockquote&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;硬件介绍：&lt;/strong&gt;       &lt;p&gt;本文主要实现了一个键盘的通用框架，可以很方便的改为不同的键盘函数，这里实现了两种按键4个单独按键和4*4行列扫描的键盘。&lt;/p&gt;      &lt;p&gt;4个按键的是这样的：四个按键分别一端接地，另一端接上拉电阻后输入单片机的P1.0-P1.3口；这样，按键按下时，单片机接到低电平，松开时单片机输入信号有上拉电阻固定为高电平。&lt;/p&gt;      &lt;p&gt;4*4的按键：行输入信号配有桑拉电阻，无按键时默认电平高电平；列扫描信号线直接接到按键列线；读键时，列扫描信号由单片机给出低电平信号(按列逐列扫描)，读取行信号，从而判断具体是哪个按键；电路图大概如下：&lt;/p&gt;      &lt;p&gt;&amp;#160;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108211130197100.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="376" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108211130397736.png" width="413" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;      &lt;p&gt;图中，IN是键盘的列扫描线，OUT是键盘的输出的行信号线。扫描是也可以按行扫描，这时IN是行扫描线，OUT的按键输出的列信号线。我的程序是按列扫描的（行列扫描原理一样，只是行列进行了交换）。&lt;/p&gt;      &lt;p&gt;这里，同时实现了4*4按键的scanf函数的移植，同时，加入了之前实现的液晶的printf函数的移植，搭建了一个可以交互输入输出的完整的一个系统；液晶的printf又加入了函数，实现了退格；可以在输入错误数字的时候退格重新输入。&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;程序实现：&lt;/strong&gt;       &lt;p&gt;先说一下程序的结构，程序实现了一个循环队列，用来存放已按下的键值，可以保存最新的四个按键，可以防止按键丢失；程序使用的是中断的方式进行按键，每16ms(用的是看门狗的间隔中断)读一次按键，进行判断键值是否有效，有效则放入队列，等待读取。&lt;/p&gt;      &lt;p&gt;循环队列的实现:用数组实现，为判断队满，数组的最后一个元素不用于存储键码值：&lt;/p&gt;      &lt;span style="color: green"&gt;/**********************宏定义***********************/&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#define &lt;/span&gt;KeySize     4           &lt;span style="color: green"&gt;//键码值队列&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#define &lt;/span&gt;Length      KeySize+1   &lt;span style="color: green"&gt;//队列数组元素个数&lt;br/&gt;/***************************************************/&lt;br/&gt;&lt;br/&gt;/**********************键值队列*********************/&lt;br/&gt;//可KeySize(Length-1)个键码循环队列占用一个元素空间&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;char &lt;/span&gt;Key[Length];    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;入队函数：入队时，队满则出队一个，以保存最新的四个按键。&lt;/p&gt;    &lt;span style="color: blue"&gt;void &lt;/span&gt;AddKeyCode(&lt;span style="color: blue"&gt;char &lt;/span&gt;keyCode)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;if&lt;/span&gt;((rear+1)%Length==front)      &lt;span style="color: green"&gt;//队满&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        front=(front+1)%Length;     &lt;span style="color: green"&gt;//出队一个&lt;br/&gt;    &lt;/span&gt;}&lt;br/&gt;    Key[rear] = keyCode;&lt;br/&gt;    rear=(rear+1)%Length;&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;出队函数：出队函数即是读取按键的函数，以供其他需要的地方调用。&lt;/p&gt;    &lt;span style="color: blue"&gt;char &lt;/span&gt;ReadKey()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;char &lt;/span&gt;temp;&lt;br/&gt;    &lt;span style="color: green"&gt;//if(rear==front) return '\0';    //无按键&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;while&lt;/span&gt;(rear==front);&lt;br/&gt;    temp = Key[front];&lt;br/&gt;    front=(front+1)%Length;&lt;br/&gt;    &lt;span style="color: blue"&gt;return &lt;/span&gt;temp;&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;KeyProcess:这个函数即是键盘处理函数，需要被每10ms-20ms的时间调用一次的函数，在这里把它放入了看门狗定时器16ms的中断中;函数流程图和函数内容如下：&lt;/p&gt;    &lt;p&gt;&amp;#160;&lt;a href="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108211130407919.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="718" alt="image" src="http://images.cnblogs.com/cnblogs_com/Engin/201108/201108211130459551.png" width="340" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;    &lt;span style="color: blue"&gt;void &lt;/span&gt;KeyProcess()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;static char &lt;/span&gt;keyValue = 0xff;    &lt;span style="color: green"&gt;//按键标识，键值&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;static char &lt;/span&gt;addedFlag = 0;      &lt;span style="color: green"&gt;//加入队列标志&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;char &lt;/span&gt;keyVal = GetKey();&lt;br/&gt;    &lt;span style="color: blue"&gt;if&lt;/span&gt;(keyVal==0xff)                &lt;span style="color: green"&gt;//无按键&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        keyValue = 0xff;&lt;br/&gt;        addedFlag = 0;&lt;br/&gt;        &lt;span style="color: blue"&gt;return&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: blue"&gt;if&lt;/span&gt;(keyValue==0xff)              &lt;span style="color: green"&gt;//之前状态无按键&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        keyValue = keyVal;&lt;br/&gt;        &lt;span style="color: blue"&gt;return&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: blue"&gt;if&lt;/span&gt;(keyValue!=keyVal)            &lt;span style="color: green"&gt;//和前次按键不同&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        keyValue = keyVal;          &lt;span style="color: green"&gt;//保存新按键值&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;return&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: blue"&gt;if&lt;/span&gt;(addedFlag==1)                &lt;span style="color: green"&gt;//已加入队列&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color: blue"&gt;return&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;    addedFlag = 1;&lt;br/&gt;    AddKeyCode(KeyCode[keyVal]);&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;这个函数完成按键的判断，并和上次的比较，从而判断是否是有效按键，再根据是否已经入队保存，去判断是否要保存，入队列保存按键。&lt;/p&gt;    &lt;p&gt;这个函数需要每10ms-20ms中断运行一次：&lt;/p&gt;    &lt;span style="color: blue"&gt;#pragma &lt;/span&gt;vector=WDT_VECTOR&lt;br/&gt;__interrupt &lt;span style="color: blue"&gt;void &lt;/span&gt;WDT_ISR()&lt;br/&gt;{&lt;br/&gt;    KeyProcess();&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;这是430看门狗的间隔定时中断，设置的是每16ms中断一次：&lt;/p&gt;        WDTCTL=WDT_ADLY_16;   &lt;span style="color: green"&gt;//看门狗内部定时器模式16ms&lt;br/&gt;    &lt;/span&gt;IE1 |= WDTIE;         &lt;span style="color: green"&gt;//允许看门狗中断&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;KeyProcess里调用了GetKey函数，这个函数需要用户提供，以满足特殊的按键需求，这里提供了两个实例：4个按键和4*4矩阵键盘。&lt;/p&gt;    &lt;p&gt;4个按键的getkey函数：&lt;/p&gt;    &lt;span style="color: blue"&gt;char &lt;/span&gt;GetKey()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;if&lt;/span&gt;((P1IN&amp;amp;0X0F)==0x0E)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue"&gt;return &lt;/span&gt;0;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: blue"&gt;if&lt;/span&gt;((P1IN&amp;amp;0X0F)==0x0D)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue"&gt;return &lt;/span&gt;1;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: blue"&gt;if&lt;/span&gt;((P1IN&amp;amp;0X0F)==0x0B)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue"&gt;return &lt;/span&gt;2;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: blue"&gt;if&lt;/span&gt;((P1IN&amp;amp;0X0F)==0x07)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue"&gt;return &lt;/span&gt;3;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: blue"&gt;return &lt;/span&gt;0xff;&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;这里根据每个按键，输出按键原始键值，没有按键则输出0xff；当自己提供getkey函数时，也需要这样，无按键时返回0xff&lt;/p&gt;    &lt;p&gt;把对应原始键值翻译成所需键码，用数组KeyCode：&lt;/p&gt;    &lt;span style="color: blue"&gt;char &lt;/span&gt;KeyCode[] = &lt;span style="color: #a31515"&gt;&amp;quot;0123&amp;quot;&lt;/span&gt;;    &lt;span style="color: green"&gt;/*4个按键时*/&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;这里把它转化成ASCII码输出，需要的话可以自行更改。&lt;/p&gt;    &lt;p&gt;4*4矩阵键盘：getkey：&lt;/p&gt;    &lt;span style="color: blue"&gt;char &lt;/span&gt;GetKey()&lt;br/&gt;{&lt;br/&gt;    P1DIR |= 0XF0;                  &lt;span style="color: green"&gt;//高四位输出&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;for&lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;i=0;i&amp;lt;4;i++)&lt;br/&gt;    {&lt;br/&gt;        P1OUT = 0XEF &amp;lt;&amp;lt; i;&lt;br/&gt;        &lt;span style="color: blue"&gt;for&lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;j=0;j&amp;lt;4;j++)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color: blue"&gt;if&lt;/span&gt;((P1IN&amp;amp;(0x01&amp;lt;&amp;lt;j))==0)&lt;br/&gt;            {&lt;br/&gt;                &lt;span style="color: blue"&gt;return &lt;/span&gt;(i+4*j);&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color: blue"&gt;return &lt;/span&gt;0xff;&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;这里是按列扫描，可以随意改成其他扫描方式，只要获取原始键值即可，无按键是须返回0xff。&lt;/p&gt;    &lt;p&gt;KeyCode，翻译成ASCII码：&lt;/p&gt;    &lt;span style="color: blue"&gt;char &lt;/span&gt;KeyCode[] = &lt;span style="color: #a31515"&gt;&amp;quot;0123456789ABCDEF&amp;quot;&lt;br/&gt;&lt;/span&gt;    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;到这里，正常的键盘程序结束，调用时只需加入Key.c，包含Key.h即可使用，先调用KeyInit后，就可以正常的读键了。这里不再细说。&lt;/p&gt;    &lt;p&gt;scanf移植：scanf移植时，需要的是ASCII码字符型设备，利用ASCII码输入数据还必须要有回车键，只有这样，才能用scanf输入数据，这里为了输入数据错误时，可以退格修改，按键还有一个退格键。&lt;/p&gt;    &lt;p&gt;键盘结构：&lt;/p&gt;    &lt;table cellspacing="0" cellpadding="0" border="1"&gt;&lt;tbody&gt;        &lt;tr&gt;          &lt;td width="52"&gt;            &lt;p&gt;1&lt;/p&gt;          &lt;/td&gt;          &lt;td width="52"&gt;            &lt;p&gt;2&lt;/p&gt;          &lt;/td&gt;          &lt;td width="52"&gt;            &lt;p&gt;3&lt;/p&gt;          &lt;/td&gt;          &lt;td width="52"&gt;            &lt;p&gt;退格&lt;/p&gt;          &lt;/td&gt;        &lt;/tr&gt;        &lt;tr&gt;          &lt;td width="52"&gt;            &lt;p&gt;4&lt;/p&gt;          &lt;/td&gt;          &lt;td width="52"&gt;            &lt;p&gt;5&lt;/p&gt;          &lt;/td&gt;          &lt;td width="52"&gt;            &lt;p&gt;6&lt;/p&gt;          &lt;/td&gt;          &lt;td width="52"&gt;            &lt;p&gt;保留&lt;/p&gt;          &lt;/td&gt;        &lt;/tr&gt;        &lt;tr&gt;          &lt;td width="52"&gt;            &lt;p&gt;7&lt;/p&gt;          &lt;/td&gt;          &lt;td width="52"&gt;            &lt;p&gt;8&lt;/p&gt;          &lt;/td&gt;          &lt;td width="52"&gt;            &lt;p&gt;9&lt;/p&gt;          &lt;/td&gt;          &lt;td width="52"&gt;            &lt;p&gt;保留&lt;/p&gt;          &lt;/td&gt;        &lt;/tr&gt;        &lt;tr&gt;          &lt;td width="52"&gt;            &lt;p&gt;保留&lt;/p&gt;          &lt;/td&gt;          &lt;td width="52"&gt;            &lt;p&gt;0&lt;/p&gt;          &lt;/td&gt;          &lt;td width="52"&gt;            &lt;p&gt;保留&lt;/p&gt;          &lt;/td&gt;          &lt;td width="52"&gt;            &lt;p&gt;回车&lt;/p&gt;          &lt;/td&gt;        &lt;/tr&gt;      &lt;/tbody&gt;&lt;/table&gt;    &lt;p&gt;保留键用字符’\0’,回车’\n’退格’\b’&lt;/p&gt;    &lt;p&gt;所以：KeyCode：&lt;/p&gt;    &lt;span style="color: blue"&gt;char &lt;/span&gt;KeyCode[] = &lt;span style="color: #a31515"&gt;&amp;quot;123\b456\000789\0\0000\0\r&amp;quot;&lt;/span&gt;; &lt;span style="color: green"&gt;/* 4*4,scanf移植*/&lt;br/&gt;&lt;/span&gt;    &lt;p&gt;在字符串里，\0后面是数字时，必须用’\000’否则，c语言编译器认为\0和后面的数字组合为一个字符。&lt;/p&gt;    &lt;p&gt;scanf的移植，需要实现getchar函数，这里和之前的getchar函数类似，把它放到了Getchar.c文件里，内容如下：&lt;/p&gt;    &lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;lt;stdio.h&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;Key.h&amp;quot;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#define &lt;/span&gt;LINE_LENGTH 20          &lt;span style="color: green"&gt;//行缓冲区大小，决定每行最多输入的字符数&lt;br/&gt;&lt;br/&gt;/*标准终端设备中，特殊ASCII码定义，请勿修改*/&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#define &lt;/span&gt;InBACKSP 0x08           &lt;span style="color: green"&gt;//ASCII  &amp;lt;--  (退格键)&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#define &lt;/span&gt;InDELETE 0x7F           &lt;span style="color: green"&gt;//ASCII &amp;lt;DEL&amp;gt; (DEL 键)&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#define &lt;/span&gt;InEOL &lt;span style="color: #a31515"&gt;'\r'              &lt;/span&gt;&lt;span style="color: green"&gt;//ASCII &amp;lt;CR&amp;gt;  (回车键)&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#define &lt;/span&gt;InLF &lt;span style="color: #a31515"&gt;'\n'                 &lt;/span&gt;&lt;span style="color: green"&gt;//ASCII &amp;lt;LF&amp;gt;  (回车)&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#define &lt;/span&gt;InSKIP &lt;span style="color: #a31515"&gt;'\3'             &lt;/span&gt;&lt;span style="color: green"&gt;//ASCII control-C&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#define &lt;/span&gt;InEOF &lt;span style="color: #a31515"&gt;'\x1A'            &lt;/span&gt;&lt;span style="color: green"&gt;//ASCII control-Z&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#define &lt;/span&gt;OutDELETE &lt;span style="color: #a31515"&gt;&amp;quot;\x8 \x8&amp;quot;     &lt;/span&gt;&lt;span style="color: green"&gt;//VT100 backspace and clear&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#define &lt;/span&gt;OutSKIP &lt;span style="color: #a31515"&gt;&amp;quot;^C\n&amp;quot;          &lt;/span&gt;&lt;span style="color: green"&gt;//^C and new line&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#define &lt;/span&gt;OutEOF &lt;span style="color: #a31515"&gt;&amp;quot;^Z&amp;quot;             &lt;/span&gt;&lt;span style="color: green"&gt;//^Z and return EOF&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;int &lt;/span&gt;getchar()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;static char &lt;/span&gt;inBuffer[LINE_LENGTH + 2];      &lt;span style="color: green"&gt;//Where to put chars&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;static char &lt;/span&gt;ptr;                            &lt;span style="color: green"&gt;//Pointer in buffer&lt;br/&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;char &lt;/span&gt;c;&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color: blue"&gt;while&lt;/span&gt;(1)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: blue"&gt;if&lt;/span&gt;(inBuffer[ptr])                       &lt;span style="color: green"&gt;//如果缓冲区有字符&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue"&gt;return &lt;/span&gt;(inBuffer[ptr++]);           &lt;span style="color: green"&gt;//则逐个返回字符&lt;br/&gt;        &lt;/span&gt;ptr = 0;                                &lt;span style="color: green"&gt;//直到发送完毕，缓冲区指针归零&lt;br/&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;while&lt;/span&gt;(1)                                &lt;span style="color: green"&gt;//缓冲区没有字符，则等待字符输入&lt;br/&gt;        &lt;/span&gt;{&lt;br/&gt;            c = ReadKey();                      &lt;span style="color: green"&gt;//等待接收一个字符==移植时关键&lt;br/&gt;            &lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt;(c == InEOF &amp;amp;&amp;amp; !ptr)              &lt;span style="color: green"&gt;//==EOF==  Ctrl+Z &lt;br/&gt;            &lt;/span&gt;{                                   &lt;span style="color: green"&gt;//只有在未入其他字符时才有效&lt;br/&gt;                &lt;/span&gt;printf(OutEOF);                 &lt;span style="color: green"&gt;//终端显示EOF符&lt;br/&gt;                &lt;/span&gt;&lt;span style="color: blue"&gt;return &lt;/span&gt;EOF;                     &lt;span style="color: green"&gt;//返回 EOF（-1）&lt;br/&gt;            &lt;/span&gt;}&lt;br/&gt;            &lt;span style="color: blue"&gt;if&lt;/span&gt;(c==InDELETE || c==InBACKSP)      &lt;span style="color: green"&gt;//==退格或删除键==&lt;br/&gt;            &lt;/span&gt;{&lt;br/&gt;                &lt;span style="color: blue"&gt;if&lt;/span&gt;(ptr)                         &lt;span style="color: green"&gt;//缓冲区有值&lt;br/&gt;                &lt;/span&gt;{&lt;br/&gt;                    ptr--;                      &lt;span style="color: green"&gt;//从缓冲区移除一个字符&lt;br/&gt;                    &lt;/span&gt;printf(OutDELETE);          &lt;span style="color: green"&gt;//同时显示也删掉一个字符&lt;br/&gt;                &lt;/span&gt;}&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color: blue"&gt;else if&lt;/span&gt;(c == InSKIP)                &lt;span style="color: green"&gt;//==取消键 Ctrl+C ==&lt;br/&gt;            &lt;/span&gt;{&lt;br/&gt;                printf(OutSKIP);                &lt;span style="color: green"&gt;//终端显示跳至下一行&lt;br/&gt;                &lt;/span&gt;ptr = LINE_LENGTH + 1;          &lt;span style="color: green"&gt;//==0 结束符==&lt;br/&gt;                &lt;/span&gt;&lt;span style="color: blue"&gt;break&lt;/span&gt;;&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color: blue"&gt;else if&lt;/span&gt;(c == InEOL||c == InLF)      &lt;span style="color: green"&gt;//== '\r' 回车=='\n'回车&lt;br/&gt;            &lt;/span&gt;{&lt;br/&gt;                putchar(inBuffer[ptr++] = &lt;span style="color: #a31515"&gt;'\n'&lt;/span&gt;);&lt;span style="color: green"&gt;//终端换行&lt;br/&gt;                &lt;/span&gt;inBuffer[ptr] = 0;              &lt;span style="color: green"&gt;//末尾添加结束符（NULL）&lt;br/&gt;                &lt;/span&gt;ptr = 0;                        &lt;span style="color: green"&gt;//指针清空&lt;br/&gt;                &lt;/span&gt;&lt;span style="color: blue"&gt;break&lt;/span&gt;;&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color: blue"&gt;else if&lt;/span&gt;(ptr &amp;lt; LINE_LENGTH)          &lt;span style="color: green"&gt;//== 正常字符 ==&lt;br/&gt;            &lt;/span&gt;{&lt;br/&gt;                &lt;span style="color: blue"&gt;if&lt;/span&gt;(c &amp;gt;= &lt;span style="color: #a31515"&gt;' '&lt;/span&gt;)                    &lt;span style="color: green"&gt;//删除 0x20以下字符&lt;br/&gt;                &lt;/span&gt;{&lt;br/&gt;                    &lt;span style="color: green"&gt;//存入缓冲区&lt;br/&gt;                    &lt;/span&gt;putchar(inBuffer[ptr++] = c);&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color: blue"&gt;else                                &lt;/span&gt;&lt;span style="color: green"&gt;//缓冲区已满&lt;br/&gt;            &lt;/span&gt;{&lt;br/&gt;                putchar(&lt;span style="color: #a31515"&gt;'\7'&lt;/span&gt;);                  &lt;span style="color: green"&gt;//== 0x07 蜂鸣符，PC回响一声&lt;br/&gt;            &lt;/span&gt;}&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;这里是支持退格等键的详细函数。&lt;/p&gt;    &lt;p&gt;如果不需要支持退格，可以简化为：&lt;/p&gt;    &lt;span style="color: blue"&gt;int &lt;/span&gt;getchar()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue"&gt;return &lt;/span&gt;ReadKey();&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;要实现scanf调用，还需要设置，详细设置参考：&lt;a href="http://www.cnblogs.com/Engin/archive/2011/07/31/2122822.html"&gt;MSP430程序库&amp;lt;四&amp;gt;printf和scanf函数移植&lt;/a&gt;；需要把库设置为CLIB；在Option-general option-library configuration里面。&lt;/p&gt;    &lt;p&gt;这样，键盘的scanf移植完成，需要使用时，只需加入对stdio.h文件的包含，然后完成键盘的初始化即可。&lt;/p&gt;  &lt;/li&gt;  &lt;li&gt;&lt;strong&gt;使用示例：&lt;/strong&gt;     &lt;p&gt;这里，示例实现的是键盘和液晶的简单交互；键盘输入数据，液晶正常显示；就像c语言调试时键盘和屏幕一样；当然没有那个丰富啦。&lt;/p&gt;    &lt;p&gt;液晶的部分，用的是原来实现的程序，在这里，为了支持输入错误时退格，对原来的printf函数加入了退格支持。具体参考：&lt;a href="http://www.cnblogs.com/Engin/archive/2011/07/31/2122822.html"&gt;MSP430程序库&amp;lt;四&amp;gt;printf和scanf函数移植&lt;/a&gt;(已经更新)。&lt;/p&gt;    &lt;p&gt;项目中接入液晶的c程序文件和printf的程序文件（Lcd12864.c、Printf.c），加入Lcd12864.h的文件包含；初始化液晶后，就可用printf向液晶输出要显示的内容了。&lt;/p&gt;    &lt;p&gt;键盘：加入Key.c，包含Key.h，加入Getchar.c，程序中初始化键盘；然后设置所用的lib为CLIB，具体设置见：&lt;a href="http://www.cnblogs.com/Engin/archive/2011/07/31/2122822.html"&gt;MSP430程序库&amp;lt;四&amp;gt;printf和scanf函数移植&lt;/a&gt;。之后就可以用键盘和液晶完成和430单片机简单的交互了。&lt;/p&gt;    &lt;p&gt;详细参考示例工程和main.c。&lt;/p&gt;    &lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;lt;msp430x16x.h&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;lt;stdio.h&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;Lcd12864.h&amp;quot;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;Key.h&amp;quot;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;long &lt;/span&gt;a;&lt;br/&gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;main( &lt;span style="color: blue"&gt;void &lt;/span&gt;)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: green"&gt;// Stop watchdog timer to prevent time out reset&lt;br/&gt;    &lt;/span&gt;WDTCTL = WDTPW + WDTHOLD;&lt;br/&gt;    ClkInit();&lt;br/&gt;    LcdInit();&lt;br/&gt;    KeyInit();&lt;br/&gt;    _EINT();&lt;br/&gt;    &lt;span style="color: blue"&gt;while&lt;/span&gt;(1)&lt;br/&gt;    {&lt;br/&gt;        printf(&lt;span style="color: #a31515"&gt;&amp;quot;请输入数字：&amp;quot;&lt;/span&gt;);&lt;br/&gt;        scanf(&lt;span style="color: #a31515"&gt;&amp;quot;%ld&amp;quot;&lt;/span&gt;,&amp;amp;a);&lt;br/&gt;        printf(&lt;span style="color: #a31515"&gt;&amp;quot;输入的数字是：%ld&amp;quot;&lt;/span&gt;,a);&lt;br/&gt;        _NOP();&lt;br/&gt;    }&lt;br/&gt;}    &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;    &lt;p&gt;这样，就可以用键盘向单片机输入数据，同时利用液晶可以很容易的知道数据输入的是否有问题。&lt;/p&gt;    &lt;p&gt;键盘的程序库就到这里，有什么不足，欢迎讨论。&lt;/p&gt;  &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;附件：&lt;a href="http://files.cnblogs.com/Engin/%E7%A8%8B%E5%BA%8F%E5%BA%93.rar"&gt;程序库&lt;/a&gt;&lt;/p&gt;&lt;p&gt;作者：&lt;b&gt;&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;给我一杯酒&lt;/a&gt;&lt;/b&gt;   &lt;br /&gt;出处：&lt;a href="http://Engin.cnblogs.com/" target="_blank"&gt;http://Engin.cnblogs.com/&lt;/a&gt;   &lt;br /&gt;本文版权归作者和博客园共有，欢迎转载，转载保留此段文字并且注明出处；谢谢。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/Engin/aggbug/2147724.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Engin/archive/2011/08/21/2147724.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
