实训Day02

2021-05-25

实训, CC2530

0x01 CC2530芯片

  • 版本:CC2530-F32/64/128/256KB分别对应32/64/128/256KB闪存
  • 内置射频收发器,具有无线能力

引脚

image-20210526111610858

  • 一共40个引脚,加上背面焊盘必须接地所以可以看作41个脚
  • 一共21个通用引脚 P0_0-P0_7,P1_0-P1_7,P2_0-P2_5,可理解成GPIO口
  • 程序下载仿真接口需5个引脚。VCC,GND,RESET,P2_1,P2_2
  • P1_0,P1_1这两个引脚IO的驱动电流能够达到20mA,其余引脚只能达到4mA
  • 30号引脚接偏置电阻,40号引脚接去耦电容,20号引脚接复位电路,25,26引脚接无线收发

0x02 什么是GPIO

  • 英文:General Purpose Input Output

  • 通用输入输出,有时简称”IO口”,既能当输入口使用,又能当输出口使用

  • 可以作为普通IO口,用来输出高电平或低电平,或者获取输入状态。同时也可以复用为片上外设功能,如UART,ADC采集通道 ,PWM输出通道,等等

  • 总结:GPIO就是芯片上一根干啥都行的引脚

  • cc2530总共有21个GPIO口,这些IO口分为3组,分别为

    ​ P0_0P0_7 P1_0P1_7 P2_0~P2_4

0x03 GPIO输入模式

  • 上拉模式

    • 默认输入时高电平,可以被外部拉低

    image-20210525144417010

  • 下拉模式

    • 默认低电平,可以外部变高

    image-20210525144606205

  • 三态模式

    • 逻辑器件:三态门
    • 除了0和1两种状态外,还有一个高阻态(电阻很大,相当于开路)
    • 高阻态:相当于该器件所在电路处于断开状态,因为不可能在实际电路中断开它

0x04 GPIO口配置

x=0,1,2,前面说过CC2530的IO口被分为3组,P0,P1,P2

1.配置PxSEL寄存器

  • 端口功能选择,设置端口是普通I/O模式还是外设模式

0–普通I/O模式,1–外设模式,默认是0

  • P2只有5个I/O口,P2_1和P2_2专门用于下载程序使用,所以不需要进行设置,P2SEL低三位分别对应P2_0,P2_3,P2_4:注意是0,3,4而不是3,4,5

2.配置PxDIR寄存器

  • 作为通用I/O口时,用来设置数据的传输方向,即设置是输出模式还是输入模式

0表示输出模式,1表示输入模式,P2是设置和PxSEL一样

3.配置PxINP寄存器

  • 在通用输入模式时,决定输入模式是上\下拉还三态模式

0表示上下拉模式,1表示三态模式

4.配置P2INP寄存器

  • 在上下拉模式确定是上拉模式还是下拉模式
  • 0表示上拉,1表示下拉
  • 由于P2IO组只有5个IO,所以该寄存器的高3位决定在配置为上下拉模式时,是上拉模式还是下拉模式。

image-20210526115438650

如P2INP &= 0xAF(1010 1111),将P0组合P1组引脚设置为上拉模式

5.实例代码

1
2
3
4
P1SEL &= 0xFB; // 1111 1011把P1_2设置为普通IO模式
P1DIR &= 0xFB; // 1111 1011把P1_2设置为输入模式
P1INP &= 0xFB; // 1111 1011 把P1_2设置为上下拉模式
P2INP &= 0xBF; // 1011 1111 把P1设置为上拉模式

0x05 什么是外部中断

  • 外部中断是单片机实时地处理外部事件的一种内部机制。当某种外部事件发生时,单片机的中断系统将迫使CPU暂停正在执行的程序,转而去进行中断事件的处理;中断处理完毕后.又返回被中断的程序处,继续执行下去。
    • 实时处理功能:在实时控制中,现场的各种参数、信息均随时问和现场而变化。这些外界变量可根据要求随时向CPU发出中断申请.请求CPU及时处珲中断请求,如中断条件
    • 故障处理功能:针对难以预料的情况或故障,如掉电、存储出错、运算溢出等,可通过中断系统由故障源向CPU发出中断请求,再由CPU转到相应的故障处理程序进行处理。

0x06 外部中断配置

  • 通用 I/O 引脚设置为输入后,可以用于产生中断。
  • 中断可以设置在外部信号的上升或下降沿触发。

1.初始化IO口

  • 设置IO口为普通IO模式,上拉输入状态

详细信息参考上文IO口配置

2.EA总中断使能(EA)

  • .EA总中断是管理着单片机是否执行中断的最大的开关,0为关,1为开

    当EA打开时,芯片才会去处理中断请求

3.组中断使能(IENx)

  • 我们知道21个I/O口是被分为了3个组
  • 每个组都有一个组中断的开关,控制着该组是否允许执行中断请求
  • 使能组中断开关需要设置IENI寄存器,如下图所示,IENI寄存器的位与端口组对应,比如我想使能P0组,那么将IENI第六位置为1即可

image-20210526200715547

image-20210526130748589

  • 从中可以看到IEN1中第5位是P1IE,端口P0组的使能开关控制,IEN2同理
1
IEN2 |= 1<<4; // 最后得到了0001 0000 1是中断使能,因此就是使能P1端口组

ps:听说新一点的iocc2530.h可以使用P0IE,P1IE,P2IE分别控制对应的组中断,但是老一点的必须使用IENx寄存器

4.引脚中断使能(PxIEN)

除了前面介绍的公共中断使能之外,每个端口还需要进行对应的使能

  • 引脚上有一个中断开关 存于PnIEN使能寄存器中
  • 针对P0_0~P0_7称为P0IEN,从低到高对应P0_0到P0_7。以此类推还有P1IEN,P2IEN。
  • 其中P2IEN比较特殊,因为P2组中只有P0-P4五个引脚,其他的是USB等用途
1
P1IEN |= 1<<2; // 0000 0010 设置P1引脚开关使能

5.设置时钟上下沿触发机制(PICTL)

在计算机中,0是低电平,1是高电平

  • 上升沿:从低电平到高电平的变化 0–>1
  • 下降沿:从高电平到低电平的变化 1–>0

在PICTL的前4位存储的就是这种触发时机

image-20210526195321256

6.设置中断处理函数(__interupt)

将前面配置配置好后便可以编写中断处理函数,声明发生中断时需要做哪些处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#pragma optimize=none // 不进行编译优化
#pragma vector=P1INT_VECTOR // P1组引发中断 PxINT_VECTOR:将x替换为引发中断的组
__interrupt void exint(void) // exint函数名可以自定义
{
if(P1IFG & 0x04) // 0x04:0000 0100
// 这里确定是P1_3发出的中断,P1IFG是P1组的中断标志位,记录每一个引脚是否有中断请求,如果为1,则要中断
{
delay_ms(100); // 消抖操作
if(P1_2 == 0) // 延时后依旧是低电平,说明确实按下了
{
// 中断要做的事情
P1_0 = !P1_0;
P1_1 = !P1_1;
}
}
// 未清除中断状态标志位中断任务会进入死循环
P1IFG = 0; // 把中断状态标志位清0
P1IF = 0; // 组中断标志位清0
}

0x07 其他

运算符

  • 使用&、|等运算可以对寄存器数据进行复位,清零,逻辑取反等操作
    • & : 与0为0,与1为本身(复位,清零)
    • ^ : 异或,相同为假,不同为真( 逻辑取反)
    • | : 或1为1,或0为本身
    • << :左移
      • 1<<2:将0x01左移两位得到0x04

代码

led_key.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include "iocc2530.h"

/*
其他注释:state不经常改变的状态,属性、灯的开关等,开了之后就不宜改变
*/

enum LED_NUM{LED0,LED1}; // 枚举0 1
enum LED_STATE{LED_OFF,LED_ON};
enum KEY_STATUS{KEY_DOWM,KEY_UP};
/*
@led_init:对led进行初始化
@retval:null
@note:LED对应的引脚是P1_0和P1_1,初始化为普通IO,输出模式
*/
void led_init(void){
P1DIR |= 0x03;// 0000 0011 把P1_0和P1_1设置为输出模式
P1SEL &= 0xFC;// 1111 1100 把P1_0和P1_1设置为普通IO模式
P1_1 = 0;
P1_0 = 0;
}

// 延时
void delay_ms(unsigned int ms) {
int i;
while(ms--)
for(i = 0;i < 100;i++);
}

/*
@led_ctrl:对LED状态进行控制函数
@led_num:指定对哪一盏LED等进行控制,可选择为LED0,LED1
@led_state:指定LED的状态,可选择为LED_ON,LED_OFF
@retval :none
*/
void led_ctrl(int led_num,int led_state) {
switch(led_num) {
case LED0:
P1_0 = led_state;
break;
case LED1:
P1_1 = led_state;
break;
}
}

/*
@key_init:按键的初始化函数
@note:按键对应的引脚是P1_2,应初始化为普通IO,上拉输入模式
@retval :none
*/
void key_init(void) {
P1SEL &= 0xFB; // 1111 1011把P1_2设置为普通IO模式
P1DIR &= 0xFB; // 1111 1011把P1_2设置为输入模式
P1INP &= 0xFB; // 1111 1011 把P1_2设置为上下拉模式
P2INP &= 0xBF; // 1011 1111 把P1设置为上拉模式
}

/*
@keystatus:获取按键的状态
@retval :按键按下返回KEY_DOWN,按键松开返回KEY_UP
*/
int key_status(void) {
if(P1_2 == 1) {
return KEY_DOWM;
} else
return KEY_UP ;
}

#pragma optimize=none // 不进行编译优化
#pragma vector=P1INT_VECTOR // P1组引发中断
__interrupt void exint(void)
{
if(P1IFG & 0x04) // 0000 0100
{
delay_ms(100);
if(P1_2 == 0)
{
// 中断要做的事情
P1_0 = !P1_0;
P1_1 = !P1_1;
}
}
P1IFG = 0; // 把中断状态标志位清0
P1IF = 0; // 组中断标志位清0
}

/*
@exit_init:外部中断初始化函数
@retval :none
@note:对应的引脚是P1_2
*/
void exit_init(void)
{
// (1)初始化IO口工作在普通IO模式,上拉输入状态
key_init();
// (2)首先打开IO口组中断允许位===>P1IE
IEN2 |= 1<<4;
// (3)打开组内对应的具体某IO口中断====>PxIEN
P1IEN |= 1<<2;
// (4)设置是上升沿还是下降沿触发===>PICTL(0,代表上升沿触发;1,代表下降沿触发)
PICTL |= 0x02; // 0000 0010 设置为下降沿触发==>PICTL(0,代表)
// (5)打开CPU总中断 EA=1;
EA = 1;
}

led_key.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef __LED_KEY_H__
#define __LED_KEY_H__

#include "iocc2530.h"
enum LED_NUM{LED0,LED1}; // ö¾Ù0 1
enum LED_STATE{LED_OFF,LED_ON};
enum KEY_STATUS{KEY_DOWM,KEY_UP};

extern void led_init(void);
extern void led_ctrl(int led_num,int led_state);
extern void key_init(void);
extern int key_status(void);
extern void exit_init(void);

#endif

杂谈

  • 内容不多,感觉学起来挺简单的,用起来还是不知道怎么搞,而且背后的内容如果更细一点,估计要学的内容够呛
  • 还有感觉学的时候有点钻牛角尖,有的时候会情不自禁的想要了解更多背后的细节,然后emmmmmm,又入门到精通,很多东西其实只要知道如何使用,有个大概了解即可
  • 今日份开心:获得一篇文章的优先读取权,文章某人还在构思中

附录

Zigbee学习日记(四)外部中断

CC2530最小系统搭建

CC2530通用IO口的输入输出