类似于纯软件编程中的hello world,单片机的入门一般从翻转IO开始,可以看到无数的教材和实验都从点亮一颗LED开始,这个实验既可以检验我们的开发环境包括单板、IDE、基础代码等是否OK,又可以让初学者所见即所得,感受自己的代码转变为对应硬件行为的有趣之处。
这篇入门博客也不免俗,我们就从翻转IO开始,但我们要到做出一个好玩的呼吸灯才结束。
1、我要准备什么?
1.1、硬件
学习单片机,由于跟硬件有关系,所以还是推荐入手一块实际的板子,无论是什么外设都不带只有一块单片机芯片的最小系统,还是带整套外设的开发板都可以。但是我自己有下面几点建议:
目前市场上,同等配置,430的板子一般比51和STM32的要贵,430芯片本身价格稍贵加之卖的没有51和STM32那么普遍,所以做好心理准备,充分了解430的优点和选型,嵌入式属于比较烧钱的兴趣,开发板会是你的第一笔投资。
下载器是容易忽略又必不可少的部分,430正版的FET调试器比较贵,个人认为没有必要花2~300买这种全系的调试器,如果你入门使用的是比较新的系列,支持SBW调试,推荐直接入手一块官方的MSP430 LAUNCHPAD,70左右同时得到了调试器和2553/2452芯片两枚。
如果入手淘宝上个人制作的开发板,请注意是否有调试器以及配置够用即可,没有必要花大价钱买所谓顶配开发板,不实用。
最后,如果是在校大学生,可以关注TI官网,LAUNCHPAD系列有可能会打折甚至免费申请,TI对教育的支持力度很大,在校学生和老师可以在官网比较容易地申请到样片。
除此之外,一台电脑也是必须的,对配置没要求,能用就行。
1.2、软件
除了CCS,还有其他的软件可以开发,比如IAR,或者使用VIM搭配430 GCC编译,后面这两种都不推荐。软件安装这里不作介绍,网上一大把,最常碰到的问题是杀毒软件拦截导致安装失败、GHOST系统被精简导致launchpad调试器驱动安装不上等,为了避免这些问题:
2、还是先点个LED试试吧
铺垫这么多,还是先老老实实点个LED试试吧。
2.1、熟悉CCS
如果一切顺利,安装完CCS并打开,你能看到这是基于ECLIPSE引入插件构成的IDE,所以具有ECLIPSE最典型的特征-workspace(工作空间)。Workspace实际上就相当于一个文件夹,你可以在里面建立很多工程。唯一值得注意的是,你对编辑器所做的所有设置均会存放于workspace下的.metadata(隐藏文件夹)文件夹中,换一个workspace,这个metadata配置不会转到新的工作空间中去,相当于换了一个新的编辑器,这也是Eclipse的优点之一。
2.2、熟悉快捷键
快捷键功能Ctrl + C\V\X\S
复制\粘贴\剪切\保存Ctrl + F
查找\替换Ctrl + H
高级查找Ctrl + /
代码自动提示Ctrl + Alt + 上\下
向上\向下复制当前行Alt + 上\下
向上\向下移动当前行Tab\Shift + Tab
向后\向前缩进F11
下载当前工程F8\Ctrl + F8
运行\暂停当前调试Alt + Shift + R
重命名当前变量其他
自己百度Eclipse快捷键
2.3、熟悉开发板
2.4、点亮LED代码
打开CCS,在最左边的工作空间右键->New->CCS Project,Target选择使用的芯片型号(比如MSP430G2553),Project name输入你的工程名字,然后下面的列表一般选择Empty Project(with main.c),但是今天我们选择Blink The LED,这样程序就自动帮我们生成了一个闪灯程序,代码如下:
#include <msp430.h> /** * blink.c */void main(void){ WDTCTL = WDTPW | WDTHOLD; // 停止看门狗 P1DIR |= BIT0; // 设置P1.0管脚为输出脚 volatile unsigned int i; // volatile ,下面的延时代码不会被编译器优化 while(1) { P1OUT ^= BIT0; // 翻转 P1.0 for(i=10000; i>0; i--); // 延时一会 }}
接下来,插上launchpad,点击顶部小虫子按钮下载代码,然后点绿箭头全速运行,你就可以看到闪烁效果。
代码解释:
P1DIR |= BIT0; // 设置P1.0管脚为输出脚
P1OUT ^= BIT0; // 翻转 P1.0
.
首先把P1设置成输出,430的管脚是可以设置的,是输出一个高低电压还是接收外界的电压输入,可以通过P1DIR来设置,BIT0BIT7分别对应PX.0PX.7管脚。那么:
将P2.3管脚设置为输出:P2DIR |= BIT3;
将P2.3管脚设置为输入:P2DIR &= ~BIT3;
.
第二句P1OUT ^= BIT0;中,P1OUT则不掌管输入输出方向了,而是管理输出的到底是高还是低电平。同理:
P2.3输出高电平:P2OUT |= BIT3;
P2.3输出低电平:P2OUT &= ~BIT3;
.那这里代码中的^=表示,设置为和当前相反,当前为高则设为低,为低则设置为高。循环执行则实现了我们的闪烁效果。
3、什么是呼吸灯?
呼吸灯是LED灯在我们的控制下,有规律的逐渐从暗变亮又变暗的过程,当我们亮暗的程度和频率把握得当时,看起来灯好像是人在呼吸一样
下面是典型的呼吸灯应用场景:开关按钮
所以呼吸灯核心是,实现亮度的均匀变化!
那么单片机是数字系统,只有高低两种状态。渐变的话要有中间不高不低的这种亮度,怎么实现呢?有一种数字系统控制模拟系统经典的办法就是—PWM调制
PWM调制的具体内容初学的话可以不用纠结,只需要跟我一起,动手改改代码就能感受到!
while(1) { P1OUT ^= BIT0; // 翻转 P1.0 //for(i=10000; i>0; i--); // 加"//"注释掉这个延时 }
有什么变化?灯是不是不闪了?那亮度呢?
什么,你跟我说很亮?那你记住现在这个亮度,让后把代码改成这样试试:P1OUT |= BIT0; // P1.0常亮
P1不再翻转,一直亮,现在这个亮度和刚刚的亮度,哪个亮?-----一样亮???好吧。。。
看到上面插USB线的那里,是不是有绿色的电源灯,很亮吧。我们下面第二个灯也是绿色的,改变下面两行,我们把灯切换到绿色的上面:
P1DIR |= BIT6; // 0改成6P1OUT ^= BIT6; // 0改成6,注意还原成^=翻转
然后,跑起来,下面的绿灯是不是亮了,和上面的电源灯比呢?是不是下面的亮度低!
原理解释:取消延时后,LED灯的亮和暗之间就不会等待一会了,会以极快的速度亮暗循环变化,亮度的变化波形和加延时是一样的,只不过速度更快了。由于人眼的暂留效应,反应不过来,就看到一直是亮的。但是由于亮和暗交替,LED实际只显示出了50%亮度的效果,看起来就比常亮的电源灯暗一半左右。
while(1) { P1OUT |= BIT0; // 亮 for(i=100; i>0; i--); // 延时100 P1OUT &= ~BIT0; // 灭 for(i=300; i>0; i--); // 延时300 }
是不是亮度更低了3. 想办法,弄个不是固定而是逐渐变化的比例,把i的长度弄成变量就可以了
#include <msp430.h>void main(void){ WDTCTL = WDTPW | WDTHOLD; // 停止看门狗 P1DIR |= BIT6; // 设置P1.0管脚为输出脚 volatile unsigned int i; // volatile ,下面的延时代码不会被编译器优化 volatile unsigned int j; // volatile ,下面的延时代码不会被编译器优化 while(1) { for(j=400; j>0; j--) { P1OUT |= BIT6; // 亮 for(i=j; i>0; i--); // 延时100 P1OUT &= ~BIT6; // 灭S for(i=400-j; i>0; i--); // 延时300 } }}
#include <msp430.h>#include <math.h>void main(void){ WDTCTL = WDTPW | WDTHOLD; // 停止看门狗 P1DIR |= BIT6; // 设置P1.0管脚为输出脚 volatile unsigned int i; // volatile ,下面的延时代码不会被编译器优化 volatile unsigned int j; // volatile ,下面的延时代码不会被编译器优化 while(1) { for(j=500; j>0; j--) { P1OUT |= BIT6; // 亮 for(i=250 + 249 * sin((2*3.14*(double)j)/500); i>0; i--); // 延时100 P1OUT &= ~BIT6; // 灭 for(i=250 - 249 * sin((2*3.14*(double)j)/500); i>0; i--); // 延时300 } }}
是不是觉得完全不是那么回事?甚至都看到灯在闪了,根本不是呼吸。这是因为代码中的sin对单片机的运算来说太复杂了,要花很长时间完成一步,打破了我们的规律性,所以我们可以把这个提前算好,放在数组里直接查询,这就是查表法,很多应用场景可以使用。这个表其实就是算好500个点从0~499对应的sin值,可以用excel生成或者matlab生成均可。
EXCEL公式:=250SIN(23.1415*(A1)/500)
#include <msp430.h>#include <math.h>const static int sin_table[500] ={3 , 6 , 9 , 13 , 16 , 19 , 22 , 25 , 28 , 31 , 34 , 38 , 41 , 44 , 47 , 50 , 53 , 56 , 59 ,62 , 65 , 68 , 71 , 74 , 77 , 80 , 83 , 86 , 89 , 92 , 95 , 98 , 101 , 104 , 106 , 109 ,112 , 115 , 118 , 120 , 123 , 126 , 129 , 131 , 134 , 137 , 139 , 142 , 144 , 147 , 149 ,152 , 154 , 157 , 159 , 162 , 164 , 166 , 169 , 171 , 173 , 176 , 178 , 180 , 182 , 184 ,186 , 189 , 191 , 193 , 195 , 197 , 198 , 200 , 202 , 204 , 206 , 208 , 209 , 211 , 213 ,214 , 216 , 218 , 219 , 221 , 222 , 223 , 225 , 226 , 228 , 229 , 230 , 231 , 232 , 234 ,235 , 236 , 237 , 238 , 239 , 240 , 241 , 241 , 242 , 243 , 244 , 244 , 245 , 246 , 246 ,247 , 247 , 248 , 248 , 248 , 249 , 249 , 249 , 250 , 250 , 250 , 250 , 250 , 250 , 250 ,250 , 250 , 250 , 250 , 249 , 249 , 249 , 248 , 248 , 248 , 247 , 247 , 246 , 246 , 245 ,244 , 244 , 243 , 242 , 241 , 241 , 240 , 239 , 238 , 237 , 236 , 235 , 234 , 232 , 231 ,230 , 229 , 228 , 226 , 225 , 223 , 222 , 221 , 219 , 218 , 216 , 214 , 213 , 211 , 209 ,208 , 206 , 204 , 202 , 200 , 199 , 197 , 195 , 193 , 191 , 189 , 186 , 184 , 182 , 180 ,178 , 176 , 173 , 171 , 169 , 167 , 164 , 162 , 159 , 157 , 154 , 152 , 149 , 147 , 144 ,142 , 139 , 137 , 134 , 131 , 129 , 126 , 123 , 120 , 118 , 115 , 112 , 109 , 106 , 104 ,101 , 98 , 95 , 92 , 89 , 86 , 83 , 80 , 77 , 74 , 71 , 68 , 65 , 62 , 59 , 56 , 53 , 50 ,47 , 44 , 41 , 38 , 34 , 31 , 28 , 25 , 22 , 19 , 16 , 13 , 9 , 6 , 3 , 0 , -3 , -6 , -9 ,-13 , -16 , -19 , -22 , -25 , -28 , -31 , -34 , -38 , -41 , -44 , -47 , -50 , -53 , -56 ,-59 , -62 , -65 , -68 , -71 , -74 , -77 , -80 , -83 , -86 , -89 , -92 , -95 , -98 , -101 ,-104 , -106 , -109 , -112 , -115 , -118 , -120 , -123 , -126 , -129 , -131 , -134 , -137 ,-139 , -142 , -144 , -147 , -149 , -152 , -154 , -157 , -159 , -162 , -164 , -166 , -169 ,-171 , -173 , -176 , -178 , -180 , -182 , -184 , -186 , -189 , -191 , -193 , -195 , -197 ,-198 , -200 , -202 , -204 , -206 , -208 , -209 , -211 , -213 , -214 , -216 , -218 , -219 ,-221 , -222 , -223 , -225 , -226 , -228 , -229 , -230 , -231 , -232 , -234 , -235 , -236 ,-237 , -238 , -239 , -240 , -240 , -241 , -242 , -243 , -244 , -244 , -245 , -246 , -246 ,-247 , -247 , -248 , -248 , -248 , -249 , -249 , -249 , -250 , -250 , -250 , -250 , -250 ,-250 , -250 , -250 , -250 , -250 , -250 , -249 , -249 , -249 , -248 , -248 , -248 , -247 ,-247 , -246 , -246 , -245 , -244 , -244 , -243 , -242 , -241 , -241 , -240 , -239 , -238 ,-237 , -236 , -235 , -234 , -232 , -231 , -230 , -229 , -228 , -226 , -225 , -223 , -222 ,-221 , -219 , -218 , -216 , -214 , -213 , -211 , -209 , -208 , -206 , -204 , -202 , -200 ,-199 , -197 , -195 , -193 , -191 , -189 , -187 , -184 , -182 , -180 , -178 , -176 , -173 ,-171 , -169 , -167 , -164 , -162 , -159 , -157 , -154 , -152 , -150 , -147 , -144 , -142 ,-139 , -137 , -134 , -131 , -129 , -126 , -123 , -120 , -118 , -115 , -112 , -109 , -106 ,-104 , -101 , -98 , -95 , -92 , -89 , -86 , -83 , -80 , -77 , -74 , -71 , -68 , -65 , -62 ,-59 , -56 , -53 , -50 , -47 , -44 , -41 , -38 , -34 , -31 , -28 , -25 , -22 , -19 , -16 ,-13 , -9 , -6 , -3 , 0};/** * blink.c */void main(void){ WDTCTL = WDTPW | WDTHOLD; // 停止看门狗 P1DIR |= BIT6; // 设置P1.0管脚为输出脚 volatile unsigned int i; // volatile ,下面的延时代码不会被编译器优化 volatile unsigned int j; // volatile ,下面的延时代码不会被编译器优化 while(1) { for(j=499; j>0; j--) { P1OUT |= BIT6; // 亮 for(i=250 + sin_table[j]; i>0; i--); // 延时 P1OUT &= ~BIT6; // 灭 for(i=250 - sin_table[j]; i>0; i--); // 延时 } }}
把这个代码输入编辑器,编译运行,呼吸灯是不是做好了?
本文使用 文章同步助手 同步