LED的操作是最为基础的实验,但我在实验过程中仍然遇到了很多问题,而这些问题是不那么容易在网上找到解答的。本篇仅讨论代码,关于IDE的配置将在另外的文章中叙述。
首先,你需要正确的、与开发板配套的电路原理图,没有它,你会走很多弯路,极大地打击像我这样的连单片机都没玩过的新手。而我从导师手里拿到的就是CC2430的原理图,上面几乎所有的管脚的标注都是错误的。而你使用的板子未必跟我用的一样,下文出现的各个端口、管脚都需要根据你手头的原理图做适当的修改才能正确的运行起来。跟下面将列举需要注意的问题。
- 引入正确的头文件
这个想必没人会出错,但还是提一下。如果使用的是CC2530就引入ioCC2530.h,使用的CC2430就引入ioCC2430.h。不要被某宝商家的资料牵着鼻子走。
- 设置端口功能寄存器
- 按位与(&,也作 AND):按位与处理两个长度相同的二进制数,两个相应的二进位都为1,该位的结果值才为1,否则为0。
- 按位或(|,也作OR):处理两个长度相同的二进制数, 两个相应的二进位中只要有一个为1, 该位的结果值为1。
- 按位抑或(^,也作XOR):对等长二进制模式按位或二进制数的每一位执行异或操作。操作的结果是如果某位不同则该位为1。否则该位为0。
- 取反(~,也作NOT):对一个二进制数的每一位执行逻辑反操作。使数字1成为0,0成为1。
- 逻辑移位(>>和<<):逻辑移位时,移位后空缺的部分全部补0。
- 设置端口方向寄存器
P1DIR是P1口的方向寄存器,占用1个字节,每一位(1~8位依次对应于P1.0~P1.7)表示该管脚的方向,0为输入,1为输出。
P0DIR |= 0x02; // 设置P0.1为输出方式(P0DIR=0000 0010) P1DIR |= 0x13; // 设置P1.0,P1.1,P1.4为输出方式(P1DIR=0001 0011)
综上,单片机里的位赋值操作可简记为:“置0用&=,置1用|=”。
- 注意有效电平
默认情况下,所有端口都是普通I/O口。如果是仅仅是LED实验,那么这一步可以省略,但为了良好的编程习惯,建议还是写上。
P0SEL &= 0x00; P1SEL &= 0x00;
我的板子上4个LED分别位于P0.1,P1.0,P1.1,P1.4,所以需要设置P0和P1两个口的功能寄存器。
P1SEL是P1口的功能寄存器,占用1个字节,每一位(1~8位依次对应于P1.0~P1.7)表示该管脚的功能,0为普通I/O口,1为外设。上面的代码将P1口的8个管脚都设置为普通I/O口。在单片机开发中,经常使用位运算符,如这里使用了&= 而不是 = 。其原因是尽可能的只操作我们想要操作的那一位,可类比于“最小权限原则”。当然这里因为用的是 &= 0x00 ,简单粗暴地把所有为都置0了,看不出效果。如果只动我们需要的位,应该这样:
P0SEL &= 0xEF; // 设置P0.1为普通I/O口(P0SEL &= 1110 1111) P1SEL &= 0xFD; //设置P1.0,P1.1,P1.4为普通I/O口(P1SEL &= 1111 1101)
这里补充一下位运算的知识[1],我在本科阶段都进行的是Web开发,从来没有使用过位运算符。单片机开发里为什么要使用 &= ,|= 着实困扰了我一段时间。
我参考的各种书籍、博客、视频都是低电平有效(包括卖我板子的那个商家!),即P1.0=0时LED点亮,P1.0=1时LED熄灭。但我拿到板子后测试发现其实这块板子是高电平有效,=1时LED点亮,=0时LED熄灭。我个人更喜欢高电平有效这种模式。
以下为LED实验的全部代码: LED.c
#include "ioCC2530.h" #define LED1 P1_0 #define LED2 P1_1 #define LED3 P1_4 #define LED4 P0_1 void initLed(void); void delay(int millisecond); /****************************************************************************** * @fn main * * @brief * Main function of application example. Flash 4 LEDs * * LED1: P1.0 * LED2: P1.1 * LED3: P1.4 * LED4: P0.1 * Parameters: * @param void * @return void ******************************************************************************/ void main( void ) { initLed(); while(1) { LED1 = 0; // 熄灭LED1 delay(500); LED2 = 0; // 熄灭LED2 delay(500); LED3 = 0; delay(500); LED4 = 0; delay(500); // 延时 LED1 = 1; // 点亮LED1 delay(500); LED2 = 1; // 点亮LED2 delay(500); LED3 = 1; delay(500); LED4 = 1; delay(500); } } // end of main() /****************************************************************************** * @fn initLed * * @brief * 初始化LED. * * Parameters: * * @param void * * @return void * ******************************************************************************/ void initLed(void) { P0SEL &= 0x00; P1SEL &= 0x00; P2SEL &= 0x00; P1DIR |= 0x13; // 设置P1.0,P1.1,P1.4为输出方式(P1DIR=0001 0011) P0DIR |= 0x02; // 设置P0.1为输出方式(P0DIR=0000 0010) } /****************************************************************************** * @fn delay * * @brief * 延时函数. * * Parameters: * * @param void * * @return void * ******************************************************************************/ void delay(int millisecond) { unsigned int i; unsigned char j; for(i = 0; i < millisecond; i++) { for(j = 0; j < 200; j++) { asm("NOP"); asm("NOP"); asm("NOP"); } } } // the end
真是高大上的东西……不愧是学院的希望
回复删除你不为“低电平有效”登高一呼吗?
删除