2014年3月11日

CC2530开发板基础实验(1)—— LED

LED的操作是最为基础的实验,但我在实验过程中仍然遇到了很多问题,而这些问题是不那么容易在网上找到解答的。本篇仅讨论代码,关于IDE的配置将在另外的文章中叙述。

首先,你需要正确的、与开发板配套的电路原理图,没有它,你会走很多弯路,极大地打击像我这样的连单片机都没玩过的新手。而我从导师手里拿到的就是CC2430的原理图,上面几乎所有的管脚的标注都是错误的。而你使用的板子未必跟我用的一样,下文出现的各个端口、管脚都需要根据你手头的原理图做适当的修改才能正确的运行起来。跟下面将列举需要注意的问题。

  1. 引入正确的头文件

    这个想必没人会出错,但还是提一下。如果使用的是CC2530就引入ioCC2530.h,使用的CC2430就引入ioCC2430.h。不要被某宝商家的资料牵着鼻子走。

  2. 设置端口功能寄存器
  3. 默认情况下,所有端口都是普通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开发,从来没有使用过位运算符。单片机开发里为什么要使用 &= ,|= 着实困扰了我一段时间。

    • 按位与(&,也作 AND):按位与处理两个长度相同的二进制数,两个相应的二进位都为1,该位的结果值才为1,否则为0。
    • 按位或(|,也作OR):处理两个长度相同的二进制数, 两个相应的二进位中只要有一个为1, 该位的结果值为1。
    • 按位抑或(^,也作XOR):对等长二进制模式按位或二进制数的每一位执行异或操作。操作的结果是如果某位不同则该位为1。否则该位为0。
    • 取反(~,也作NOT):对一个二进制数的每一位执行逻辑反操作。使数字1成为0,0成为1。
    • 逻辑移位(>>和<<):逻辑移位时,移位后空缺的部分全部补0。
  4. 设置端口方向寄存器

    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用|=”。

  5. 注意有效电平
  6. 我参考的各种书籍、博客、视频都是低电平有效(包括卖我板子的那个商家!),即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

2 条评论:

  1. 真是高大上的东西……不愧是学院的希望

    回复删除
    回复
    1. 你不为“低电平有效”登高一呼吗?

      删除