CC2530单片机技术与应用学习笔记

CC2530介绍:

CC2530 结合了领先的RF 收发器的优良性能,业界标准的增强型8051 CPU,系统内可编程闪存,8-KB RAM 和许多其它强大的功能。CC2530 有四种不同的闪存版本:CC2530F32/64/128/256,分别具有32/64/128/256KB 的闪存。CC2530 具有不同的运行模式,使得它尤其适应超低功耗要求的系统。运行模式之间的转换时间短进一步确保了低能源消耗

模块介绍:

  1. IAR软件创建工程
  2. IO端口
  3. 外部中断
  4. 定时/计数器
  5. UART串口
  6. ADC转换
  7. 看门狗

一、使用IAR建立工程

  1. 先创建一个空的文件夹在D盘,并命名(如LED-TEST)
  2. 单击Project,选择Create New Project
  3. 选中Empty project,点击OK
  4. 输入文件名,将工程保存在已建立的文件夹中
  5. 点击File--->>New--->>File创建一个新的.c文件
  6. 点击File--->>Save保存.c文件
  7. 点击File--->>SaveWokespace保存工作区
  8. 鼠标右键Workspace的文件夹点击Add,将.c文件添加进工作区
  9. 右键单击Files,选择option,点击Device后的...,打开TexasInstruments文件夹,并选择CC2530F256
  10. 最后点击Debugger,选择Driver框的Texas Instruments

ps:配置以上只适合仿真,烧录需要另外配置Linker

最后输入代码,点击编译出现0错误0警告

#include<ioCC2530.h>

void main()
{
  while(1)
  {
    
  }
}

二、IO端口

CC2530单片机采用QFN40封装,拥有40个引脚,21个IO口,P0和P1端口组各有8个IO口,P2端口只有5个IO口。

IO口可通过程序控制输入输出模式,输出模式指对外输出高低电平来控制相关电路的高低电平;输入模式指直接读取IO端口的逻辑电平

输入端口的三种模式

  • 上拉模式(使用按键)
  • 下拉模式
  • 三态模式(ADC转换使用)

 IO端口的寄存器

 

 

具体使用流程图

 操控寄存器P1SEL和P1DIR来实现D3灯的闪烁

#include<ioCC2530.h>

#define uchar unsigned char 
#define uint unsigned int

#define D3 P1_0
#define D4 P1_1
#define D5 P1_3
#define D6 P1_4

//延时函数
void delay(uint t)
{
  while(t--);
}
//初始化led灯的端口
void Init_LED()
{
  //将led的端口设置为通用IO口 清零操作
  P1SEL&=~0X1B;
  //将led的端口设置为输出方向 置一操作
  P1DIR|=0X1B;
  //关闭led
  P1&=~0X1B;
}

void main()
{
  Init_LED();
  
  while(1)
  {
    D3=1;
    delay(60000);
    D3=0;
    delay(60000);
  }
}

 操控按键实现LED的的亮灭

#include<ioCC2530.h>

#define uchar unsigned char 
#define uint unsigned int

#define D3 P1_0
#define D4 P1_1
#define D5 P1_3
#define D6 P1_4
#define SW1 P1_2

//延时函数
void delay(uint t)
{
  while(t--);
}

//初始化IO口
void Init_IO()
{
  //将led的端口设置为通用IO口 清零操作
  P1SEL&=~0X1B;
  //将led的端口设置为输出方向 置一操作
  P1DIR|=0X1B;
  //将P1_2口设置为通用IO口 0000 0100
  P1SEL&=~0X04;
  //P1_2口设置为输入方向
  P1DIR&=~0X04;
  //INP设置为带上拉
  P1INP&=~0X04;
  P2INP&=~0X20;
  //关闭led
  P1&=~0X1B;
}

void Scanf_Key()
{
  //判断按键是否按下
   if(SW1==0)
   {
     //按键消抖
     delay(100);
     //如果按键还处于按下的状态
     if(SW1==0)
     {
       D3=~D3;
     }
   }
}

void main()
{
  Init_IO();
  
  while(1)
  {
   Scanf_Key();
  }
}


三、中断

CC2530具有18个中断源

中断的相关概念:

(1)中断源:引起中断的原因(发出中断申请的来源),如外部中断,定时器中断,ADC中断。

(2)中断请求:中断源要求CPU提供服务的请求,当有中断请求时,对应的标志位会被置位

(3)中断服务函数,CPU响应后执行的响应处理程序。

(4)中断向量:中断服务函数的入口地址。

中断类型

1.外部中断:单片机外部产生的中断,如IO端口输入由高变低或由低变高,最常见的是按键中断

2.内部中断:如定时器Timer,串口Uart,模数转换ADC等。

使能端口组(寄存器IEN0,IEN1,IEN2

每个中断源都有一个中断开关,要使用中断功能,就需要开启中断功能开关,

所使用的寄存器有IEN0,IEN1,IEN2;其中IEN0和IEN1可位寻址IEN2不可位寻址(可位寻址是指可以单独对寄存器的位进行操作,而不可位寻址是指要中断使能的时候只能对整个寄存器进行操作)

如:对IEN1寄存器的P0IE中断使能时可以写成:P0IE=1;

        而对IEN2寄存器的P1IE中断使能时可以写成:IEN2 |= 0X10;

IEN0寄存器

IEN1寄存器

IEN2寄存器

P0IEN和P1IEN寄存器

使能端口组后,还需要设置当前端口组中具体那几个端口有外部中断功能,将不需要的端口屏蔽掉,如使能P1_2端口可写成: P1IEN |=0X04;

设置中断触发方式

(1)高低电平触发

(2)上升沿下降沿边沿触发

要设置触发方式,则需要设置它的PICTL寄存器

如设置P1_2端口下降沿触发,则为PICTL|=0X02;

中断寄存器配置流程

通过按键中断控制跑马灯启停
#include<ioCC2530.h>

#define uchar unsigned char
#define uint unsigned int

#define D3 P1_0
#define D4 P1_1
#define D5 P1_3
#define D6 P1_4

#define SW1 P1_2

uchar F_LED = 1;

void delay(uint t){
  while(t--){
      while(F_LED==0);
  }
}

void Led_Test(){
    P1SEL&=~0X1B;
    P1DIR|=0X1B;
    
    P1|=0X1B;
    P1&=~0X1B;
    
}

void Led_Running(){
  while(1){
    
      D4=1;
      D3=0;
      D6=0;
      D5=0;
      delay(60000);
      
      
      D4=0;
      D3=1;
      D6=0;
      D5=0;
      delay(60000);
      
      
      D4=0;
      D3=0;
      D6=1;
      D5=0;
      delay(60000);
      
      
      D4=0;
      D3=0;
      D6=0;
      D5=1;
      delay(60000);
      
      
      
  }
}

void Init_SW1(){
    P1SEL&=~0X04;
    P1DIR&=~0X04;
    P1INP&=~0X04;
    P2INP&=~0X40;
    
    IEN2|=0X10;
    P1IEN|=0X04;
    PICTL|=0X02;
    EA=1;
}

#pragma vector = P1INT_VECTOR
__interrupt void P1Int(){
  if((P1IFG&0X04)==0X04){
    if(F_LED==1){
        F_LED=0;
    }
    else{
        F_LED=1;
    }
      
      
  }
    P1IFG&=~0X04; //对引脚清零
    P1IF=0;  //对整个外部中断引脚端口清零
}

void main(){
  Led_Test();
  Init_SW1();  
  while(1){
     Led_Running();
  }
}

每当端口组产生中断时,该端口组的中断标志位就会置一,该标志位需要手动软件清零。


四、定时/计数器

定时/计数器概念:
对时钟信号或外部输入信号进行计数,当达到设定要求的值产生溢出时便向CPU提出处理请求,实现定时计数功能的外设。
定时器功能:

(1)定时器功能

(2)计算器功能

(3)输入捕获

(4)输出比较

(5)PWM功能

CC2530具有5个定时器

(1)定时器1是一个16位定时器,能够计算65536个脉冲,支持输入捕获,输出比较,PWM功能,具有自由运行模式,模模式,正计数/倒计数模式三种工作模式,是CC2530功能最为齐全的定时器。

(2)定时器2用于算法提供定时,一般不使用.

(3)定时器3/4是8位定时器,能够计数256个脉冲,支持输入捕获,输出比较,具有自由运行模式,倒计数,模模式,正计数/倒计数模式四种工作模式,

(4)睡眠定时器,是一个24位正计数定时器,运行在32kHz的时钟频率下。主要用于设置进入和退出低功耗模式之间的周期。

定时器的工作模式

(1)自由运行模式:从0X0000开始计数到0XFFFF时,重新载入从0开始计数

(2)模模式:与自由运行模式一样,但是可以自己设置最大值(溢出值)

(3)正计数/倒计数模式:从0X0000开始计数到最大值后,再从最大值计数到0X0000,。

使用定时器时需要初始化TxCTL

定时时间计算公式

设置定时时间需要向高八位TxCCxH和低八位TxCCxL寄存器写入值

代码

#include<ioCC2530.h>

#define uchar unsigned char
#define uint unsigned int

#define D3 P1_0
#define D4 P1_1
#define D5 P1_3
#define D6 P1_4

uint t1_count = 0; //计数器,每达到0.1s count++



void Init_Led(){
    P1SEL&=~0X1B;
    P1DIR|=0X1B;
    //P1|=0X1B;
    P1&=~0X1B;
    
}

void Init_T1(){
  
    //设置高8位和低8位的值
    T1CC0L=0XD4;
    T1CC0H=0X30;
    //模模式开启通道输出比较模式
    T1CCTL0|=0X04;
    //打开中断允许位
    T1IE=1;
    //打开总中断
    EA=1;
    //设置工作模式和时钟分频
    T1CTL|=0X0E;
    
}

#pragma vector = T1_VECTOR
__interrupt void T1vector(){
    //T1STAT&=~0X20;
    t1_count++;
    if((t1_count%10)==0){
        D4=~D4;
        
    }
    if(t1_count==40){
        D6=~D6;
        t1_count=0;
    }
    
}

void main(){
  Init_Led();
  Init_T1();
}

定时器初始化流程


五、UART串口

串口通讯:

指外设与计算机通过数据线,地线,时钟线按位进行数据传输的通信方式。

通信方式

(1)单工模式:一方发送,一方接收,信息只沿一个方向传输,使用一根数据线。

(2)半双工模式:使用一根数据线,既能发送又能接收,但不能同时收发,

(3)全双工模式:有两条线,既能发送也能接收。

波特率:每秒钟传输的数据位。

CC2530有两个串行接口USART0和USART1,分别能够运行于异步USART模式和同步SPI模式。

USART引脚映射

使用到的寄存器

 

波特率设置 

 

 PERCFG寄存器

串口初始化模板

示例代码
#include<ioCC2530.h>

#define D5 P1_3
#define uchar unsigned char
#define uint unsigned int

void delay(uint t){
    while(t--);
}

void Init_LED(){
    P1SEL&=~0X1B;
    P1DIR|=0X1B;
    
    P1|=0X1B;
    delay(60000);
    P1&=~0X1B;
}

//看门狗初始化为定时器模式且时间为1s;因为没有用到中断所以不需要打开中断使能
void Init_WDT(){
  
    WDCTL=0X0C;
    //IEN2|=0X20;
    //EA=1;
}

//初始化串行口
void Init_UART(){
  //IO引脚映射到备用位置1
    PERCFG&=~0X01;
    P0SEL|=0X0C;
  //波特率设置为9600 
    U0BAUD=59;
    U0GCR=8;
  //两个寄存器的控制 控制寄存器和控制和状态寄存器 
    U0UCR|=0X80;  //1000 0000 ; 清除单元
    U0CSR|=0XC0;  //1100 0000 ; 模式选择为UART模式,且打开接收使能
    
   // UTX0IF=0;
    //URX0IF=0;
    
    //没有用到中断所以可以不打开
    //IEN2|=0X04;
    //URX0IE=1;
    //EA=1;
}

//切换为32MHZ频率
void Init_CLK32(){
    CLKCONCMD&=~0X40;
    while(CLKCONSTA&0X40);
    CLKCONCMD&=~0X07;
    
}

//发送字位函数
void UR0_SendByte(uchar dat){
    U0DBUF=dat;  //是UXBUF寄存器
    while(UTX0IF==0);  //UATR的中断标志位,要手动清零;等待UTX0IF=1时清零
    UTX0IF=0;
}

//发送字符串
void UR0_SendString(uchar *str){   //参数字符串为指针
  while(*str!='\0'){               //字符串最后一位是\0
    UR0_SendByte(*str++);          //调用发送字节的函数
  }
}

void main(){
  Init_CLK32();
  Init_LED();
  Init_WDT();
  Init_UART();
  while(1){
    if(WDTIF==1){
       WDTIF=0;
       D5=1;
       UR0_SendString("Hello Word!\r\n");
       D5=0;
    }
  }
}


六、ADC转换

ADC是将输入的模拟信号转化为数字信号,如速度,光照,压力等,连续变化的物理量转化为相对于的电压和电流模拟信号。

模拟信号和数字信号

CC2530的ADC模块支持最高14位二进制的模拟数字转化,具有12位有效位,具有8个可配置通道,以及一个参考电压发生器。

使用到的寄存器

APCFG寄存器 (使用具体端口时需要开启)

ADCH和ADCL寄存器(ADC转化完成后将值存入此)

ADCCON1(当转换完成后ADCCON1第七位会置1)

ADCCON3(单次转换使用)

ADC转换后,获取的高八位值和低八位值需要进行处理

ADC_number=ADCH;        //先获取高八位的值

ADC_number=(ADCH<<8)|ADCL;  //将低八位的值装入

ADC_number=ADC_number>>5(取10位有效位)2^10=1023份

ADC_Vol=(3.3/1023)*ADC_number; //最后的值

ps:取有效位计算

具体代码

以查询方式来开启ADC采样

#include<ioCC2530.h>
#include<stdio.h>

#define D5 P1_3
#define uchar unsigned char
#define uint unsigned int

uint adc_number=0;
uchar str[128];

//初始化LED
void Init_LED(){
    P1SEL&=~0X1B;
    P1DIR|=0X1B;
    P1|=0X1B;
    P1&=~0X1B;

}

//看门狗设置为定时器模式 1s定时
void Init_WDT(){
    WDCTL|=0X0C;
    //IEN2|=0X20;
    //EA=1;

}

//将系统时钟转为32MHZ
void Init_CLK(){
    CLKCONCMD&=~0X40;
    while(CLKCONSTA&0X40);
    CLKCONCMD&=~0X07;

}

//初始化串口 UART模式 映射到UART0备用位置1 波特率设置为9600
void Init_UART0(){
    PERCFG&=~0X01;
    P0SEL|=0X0C;
    
    U0BAUD=59;
    U0GCR=8;
    
    U0UCR|=0X80;
    U0CSR|=0X0C;
    
    UTX0IF=0;
    URX0IF=0;

}

//写一个字位
void Send_Byte(uchar dat){
     U0DBUF=dat;
     while(UTX0IF==0);
     UTX0IF=0;

}

//写一个字符串
void Send_String(uchar *str){
  while(*str!='\0'){
      Send_Byte(*str++);
  }

}

//初始化ADC P0_0模拟io启用
void Init_ACD(){
    APCFG|=0X01;
    //ADCCON|=0XA0;
    

}

void Start_ADC_GetValue(){
    D5=1;
    ADCCON3|=0XA0;  //1010 0000 AVDD5作为参考电压 256抽取率 AIN0位通道选择
    while((ADCCON1&0X80)!=0X80);  //读取ADCCON1寄存器,如果完成转换,第7位将被置1 1000 0000===》0x80 可以查询ADCIF标志位,但要软件清零
    adc_number=ADCH;//将读取到的高八位传给adc_number
    adc_number=(adc_number<<8 | ADCL); //将高八位左移8位,或上低8位得到读取到的16位值
    adc_number=adc_number>>2; //低八位的1和0为无效位,所以要右移两位得到完整的值
    
    sprintf((char *)str,"AIN0的采样结果为:%d\r\n",adc_number);
    Send_String(str);
    D5=0;

}

void main(){
    Init_CLK();
    Init_LED();
    Init_WDT();
    Init_UART0();
    Init_ACD();
    while(1){
      if(WDTIF==1){
          WDTIF=0;
          Start_ADC_GetValue();
      
      }
   }
}

以中断方式获取ADC

#include<ioCC2530.h>
#include<stdio.h>

#define uchar unsigned char
#define uint unsigned int
#define D5 P1_3

uint number=0;
uchar str[128];

void Init_LED(){
  
    P1SEL&=~0X1B;
    P1DIR|=0X1B;
    P1&=~0X1B;

}

void Init_WDC(){
  
    WDCTL|=0X0C;

}

void Init_CLK32(){
  
    CLKCONCMD&=~0X40;
    while(CLKCONSTA&0X40);
    CLKCONCMD&=~0X07;

}

void Init_UART0(){
    
    PERCFG&=~0X01;
    P0SEL|=0X0C;
    
    U0BAUD=59;
    U0GCR=8;
    
    U0UCR|=0X80;
    U0CSR|=0XC0;

}

void Send_byte(uchar dat){
    U0DBUF=dat;
    while(UTX0IF==0);
    UTX0IF=0;
}

void Send_String(uchar *str){
  while(*str!='\0'){
      Send_byte(*str++);
  }
}

void Init_ADC(){
    APCFG|=0X01;
    ADCIE=1;
    EA=1;
}

#pragma vector=ADC_VECTOR
__interrupt void ADC_Running(){
        
        
        number=ADCH;
        number=(number<<8)|ADCL;
        number=number>>2;
        sprintf((char *)str,"AIN0的采样结果是%d\r\n",number);
        Send_String(str);
        D5=0;
        
    
    

}

void main(){
  Init_CLK32();
  Init_LED();
  Init_WDC();
  Init_UART0();
  Init_ADC();
  while(1){
    
    if(WDTIF==1){
        WDTIF=0;
        D5=1;
        ADCCON3|=0XB0;
    }
      
  }
}

七、看门狗(Watch Dog Timer)

CC2530的看门狗定时器是一个安全功能,用于防止程序运行死锁或进入错误状态。看门狗定时器需要定期“喂狗”,也就是通过软件对其进行重置,以防止它超时并导致设备重启。

直接点理解看门狗就是个定时器,程序开始运行的时候开始计数,当计数值溢出,没有喂狗操作的时候WDT就使系统复位。

程序运行过程中,每隔一段时间内核发出指令让看门狗重新计数(喂狗),在最大间隔时间内,通过喂狗,系统就不会实现自动复位。

看门狗有两种模式

1.看门狗模式(用来监视系统)

2.定时器模式(和定时器一样,有四个可选的定时时间)

ps:定时器模式会产生中断请求

看门狗定时器控制寄存器WDCTL

喂狗序列:在看门狗时钟周期内,写入0XA到WDCTL.CLR;然后写入0X5到同一个寄存器位

通过代码实现两个LED闪烁8次,一个灯的闪烁带喂狗程序,一个灯的闪烁不带喂狗程序。

#include<ioCC2530.h>

#define uchar unsigned char
#define uint unsigned int

#define D3 P1_0
#define D4 P1_1
#define D5 P1_3
#define D6 P1_4



//延时函数
void delay(uint t)
{
    while(t--);
}

//初始化LED
void Init_Led()
{   //配置灯的寄存器
    P1SEL&=~0X1B;
    P1DIR|=0X1B;
    
    //把四个LED灯闭关
    P1&=~0X1B;    
}

//初始化看门狗
void Init_Wdt()
{
  //0000 1000 设置为看门狗模式
  WDCTL=0X08;
}

//喂狗程序
void FeedWD()
{
  WDCTL|=0XA0;
  WDCTL|=0X50;
}

//带喂狗的led闪烁
void Feed_Led()
{
    D4=1;
    delay(60000);
    delay(60000);
    D4=0;
    delay(60000);
    delay(60000);
    FeedWD();
    
}

//不带喂狗的led闪烁
void NOTFEED_Led()
{
    D6=1;
    delay(60000);
    delay(60000);
    D6=0;
    delay(60000);
    delay(60000);
}

void main()
{
  Init_Led();
  Init_Wdt();
  uint i=0;
  while(1)
  {
    for(i=0;i<8;i++)
    {
        Feed_Led();
    }
    for(i=0;i<8;i++)
    {
        NOTFEED_Led();
    }
     
  }

}

最后观察可以看到,带喂狗程序的灯可以完整的闪烁8次,不带喂狗程序的灯在在看门狗时钟周期完成后直接被复位,不能正常闪烁8次

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值