`
hulianwang2014
  • 浏览: 690064 次
文章分类
社区版块
存档分类
最新评论
  • bcworld: 排版成这样,一点看的欲望都没有了
    jfinal

CC2430 串口使用详解

 
阅读更多
为了完成课题,最近下定决心学习CC2430。网上的资料很多,重复的部分不做过多的介绍,没有的部分做一下少许的补充,希望对大家有用!【建议各位使用更新的CC2530,该芯片为CC2430的替代版本】

全部代码如下,先看一下整体!

//头文件
#include "hal.h"
#include "stdio.h"
// 函数声明
UINT8 UART0_Init();

void main(){
    //使用外部时钟
     SET_MAIN_CLOCK_SOURCE(CRYSTAL);
    //串口初始化
     UART0_Init();
    //字符输出 输出1
    putchar('1');
    //字符串输出 输出Hello CC2430
    printf("Hello CC2430!\n");
    while(1){
   }
}

int putchar(int c){
    if(c== '\n'){
      while(!UTX0IF);
      UTX0IF = 0;
      U0DBUF = '\r';
    }
    while(!UTX0IF);
    UTX0IF = 0;
    U0DBUF = c;
	  return c;
}

UINT8 UART0_Init(){
    //UART0 IO口定位
    IO_PER_LOC_UART0_AT_PORT0_PIN2345();
    //9600 8 N 1
   UART_SETUP(0,9600,HIGH_STOP);
   UTX0IF = 1;
   return 0;
}

下面一步一步分析一下

1头文件

#include "hal.h" 该头文件包括了操作CC2430常用寄存器的宏,书中找到的觉得很实用。

#include "stdio.h" 调用printf函数,重定义putchar函数

2 定义系统时钟 SET_MAIN_CLOCK_SOURCE(CRYSTAL);

设定了CC2430的时钟频率,即使用片外32MHz。根据数据手册,CC2430可以有两种时钟,第一种是片外的32M石英晶振,另一种是片内的16M的RC振荡器。顺便说一下,这个SET_MAIN_CLOCK_SOURCE() 是一个名为hal.h文件中的“动作宏”。我手头有一本书,名为《ZigBee技术实践教程》,其中的代码都使用了这个头文件。该头文件中有很多的API函数,若仔细的查看代码,配合数据手册页可以看懂其中各宏的“原理”。设定时钟的的函数原型是这样的:

#define SET_MAIN_CLOCK_SOURCE(source) \
   do {                               \
      if(source) {                    \
        CLKCON |= 0x40;               \
        while(!HIGH_FREQUENCY_RC_OSC_STABLE); \
        if(TICKSPD == 0){             \
          CLKCON |= 0x08;             \
        }                             \
        SLEEP |= 0x04;                \
      }                               \
      else {                          \
        SLEEP &= ~0x04;               \
        while(!XOSC_STABLE);          \
        asm("NOP");                   \
        CLKCON &= ~0x47;              \
        SLEEP |= 0x04;                \
      }                               \
   }while (0)


对应着数据手册,完全可以看懂其中的“玄机”。由于我还处在学习CC2430的初级阶段,以后就根据这个头文件编写程序。至于寄存器的话,大概知道其中的作用即可

领悟到的小技巧:

1 如果需要使用一个复杂的动作宏的话,多行书写使用 \ 。

2 所有的这些动作都包含在 do{} while(0)中。

3 定义IO口IO_PER_LOC_UART0_AT_PORT0_PIN2345();

这句话把UART0的IO口定义到P02 P03 P04 P05。函数原型是这样的:

#define IO_PER_LOC_UART0_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x01)|0x00; } while (0)

4 设定串口相关参数UART_SETUP(0,9600,HIGH_STOP);

函数原型是这样的:

#define UART_SETUP(uart, baudRate, options)      \
   do {                                          \
      if((uart) == 0){                           \
         if(PERCFG & 0x01){                      \
            P1SEL |= 0x30;                       \
         } else {                                \
            P0SEL |= 0x0C;                       \
         }                                       \
      }                                          \
      else {                                     \
         if(PERCFG & 0x02){                      \
            P1SEL |= 0xC0;                       \
         } else {                                \
            P0SEL |= 0x30;                       \
         }                                       \
      }                                          \
                                                 \
      U##uart##GCR = BAUD_E((baudRate),CLKSPD);  \
      U##uart##BAUD = BAUD_M(baudRate);          \
                                                 \
      U##uart##CSR |= 0x80;                      \
                                                 \
                                                 \
      U##uart##UCR |= ((options) | 0x80);        \
                                                 \
      if((options) & TRANSFER_MSB_FIRST){        \
         U##uart##GCR |= 0x20;                   \
      }                                          \
   } while(0)


5UTX0IF = 1; UART0发送完成标志位1

若串口数据发送完成,该寄存器被置位。若寄存器被置位,需要通过软件清零。这个也是很好理解的。

6putcharprintf函数

说完了初始化,再来谈谈如何使用putcharprintf函数。Putcharprintf都是C语言标准库函数。Printf调用putchar实现字符数据的传送。翻看IAR的代码,获得了使用putchar函数的信息。IAR中来了一段51单片机的代码。该代码位于EW8051_CompilerReference文件中。其中有这么一段参考代码。

#include <io8052.h> 
int putchar(int c)  { 
if (c == '\n') { 
while (!SCON_bit.TI); 
SCON_bit.TI = 0; 
SBUF = 0x0d; 
} 
while (!SCON_bit.TI); 
SCON_bit.TI = 0; 
return (SBUF = c); 
}

这段代码有点51基础的都可以看懂。唯一需要说明的就是,如果出现转义字符\n(回车)的话,先输出转义字符\t(换行)。简单说,windows喜欢先来换行(\r),再来回车(\n)。而linux中只要一个回车就OK

同理,CC2430的代码就是可以这样写:

int putchar(int c){
    if(c== '\n'){
      while(!UTX0IF);
      UTX0IF = 0;
      U0DBUF = '\r';
    }
    while(!UTX0IF);
    UTX0IF = 0;
    U0DBUF = c;
	  return c;
}

7 IARprintf参数设置

接下来必须说说IAR中相关的设置,在EW8051_UserGuide中,指出了printfscanf函数的相关设置。printf包含了small medium large三个选项。每个选型包含不同的printf功能,当然功能越全,消耗的资源也就越多。在这里我就先设置成small了。IAR的说明文件中也给出了这个选项参数所提供的功能,如下表所示。

8实验结果

最后给出实验的结果,虽然代码非常的简单,但是我还是花了一整个下午去调试,后来发现其实是IAR中的link中某参数选择错误了。实验的结果还是预想的那样,使用的时候还是要注意串口的参数设定,CC2430的串口调试助手的参数要一致。

总结

串口的使用非常的重要,它是PC机和单片机的重要桥梁。现在,单片机负责采集数据,而PC机负责分析处理数据。在这个示例代码中,通过使用hal头文件,避免了复杂难记的寄存器操作,从而快速的初始化串口;通过改写putchar函数,写出了适合CC2430串口输出的函数;最后使用了标准的printf函数实现了串口输出。


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics