+
+

电工实习(一)基础GPIO实验

之前短期的电赛培训里虽然有学MSP430,但是那时候都是引用学长写好的库函数,离底层太远,人太飘。

微控制器(MCU)、微处理器(MPU)和数字信号处理器(DSP)是目前最常用的3种可编程处理器。本课程所学的单片机MSP430属于微控制器。

  • 特点:小巧灵活,成本低,易于产品化;抗干扰能力强。
  • 应用:智能仪器仪表,变电站

由于是软件设计部分,所以还提了一下软件开发流程:

1
2
项目立项 -> 需求定义 -> 系统设计 -> 编码开发 -> 版本发布 -> 缺陷跟踪  
集成测试 系统发布 跟踪维护

回到硬件,依旧是熟悉的MSP430F5529的Launch Pad和配套的BoosterPack。由于是第一堂课,所以实验内容也还是熟悉的点亮LED🤦🏻‍♂️。

不过不同于之前的培训,这次要求用两种方法实现,分别是调用头文件法和使用固件库配置GPIO引脚控制法。(其实还有一种配置寄存器法,但是老师说这是架构师该操心的所以不要求)

实验内容

由于还没学数电,加上计算机组成原理这方面的知识完全靠以前看闲书的积淀,所以实验时并不清楚寄存器和位运算为何物。

寄存器
寄存器是CPU的有限存贮容量的高速存贮部件,用来暂存指令、数据和地址。

  • PxDIR:方向控制寄存器;1为输出,0为输入,默认为输入
  • PxIN(只读):读取引脚的值
  • PxOUT:0为低电平/引脚拉低,1为高电平/引脚拉高
  • PxREN:用于启用上拉/下拉电阻(先要用PxDIR设置为输入),与PxOUT配合使用
  • PxIFG 中断标志寄存器
  • PxIE 允许中断寄存器
  • PxIES 中断边沿选择寄存器
PxDIR PxREN PxOUT I/O配置
0 0 X 输入,禁用电阻
0 1 0 输入,下拉
0 1 1 输入,上拉
1 X X 输出,PxREN无效

位运算

  • & 按位与:A&0=0 A&1=A
  • | 按位或:A|0=A A|1=1
  • ^ 按位异或
  • ~ 按位取反
  • << 左移,右边补0,溢出舍弃;左移1位相当于乘2
  • >> 右移,无符号数高位补0,低位舍弃;右移1位相当于除以2

运算量只能是整型或字符型的数据,不能为浮点型。

调用头文件方法

思路:初始化引脚 -> 逻辑判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <msp430.h>

void InitTo()
{
P8DIR |= BIT1;//设置P8.1为输出
P1DIR &=~ BIT2; //设置P1.2为输入
P1REN = BIT2; //设置上拉电阻
P1OUT = BIT2;
}

int main(void)
{
WDTCTL = WDTPW | WDTHOLD; //关闭看门狗
InitTo();
while(1)
{
if (P1IN&BIT2) P8OUT |= BIT1;
else P8OUT &=~ BIT1;
}
}

常用位运算操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//设置P1.0输出并设置高电平  
P1DIR | = BIT0;
P1OUT | = BIT0;

//设置P1.4输出并设置低电平
P1DIR | = BIT4;
P1OUT &=〜 BIT4;

//设置多个引脚输出并设置电平
P1DIR | = BIT4 | BIT6;
P1OUT | = BIT4 | BIT6;

//将端口1的所有引脚设为输出并将其设置为高电平
P1DIR = 0xFF;
P1OUT = 0xFF;

//设置上拉电阻
P1DIR&=〜BIT3;
P1REN = BIT3;
P1OUT = BIT3;

固件库配置GPIO方法

原理:调用TI官方库函数。
所以要先在Resource Explorer中下载对应的库函数(可能需要科学上网),如果在View下找不到Resource Explorer,可能是在Getting Started中将CCS设置为了Simple模式,取消即可。

库函数路径如下图,先点击右上角第三个按钮Download and Install之后,再点击中间的按钮导入到IDE。

之后,就可以在新导入的空项目中愉快地玩耍了。
运用库函数编码会容易许多,因为函数的名字非常的easy。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "driverlib.h"

void InitIo()
{
GPIO_setAsOutputPin(GPIO_PORT_P8,GPIO_PIN1);//设置P8.1为输出
GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1,GPIO_PIN2);//设置P1.2为输入并设置上拉电阻
}

void main (void)
{
InitIo();
if (GPIO_getInputPinValue(GPIO_PORT_P1,GPIO_PIN2))
GPIO_setOutputLowOnPin(GPIO_PORT_P8,GPIO_PIN1);
else
GPIO_setOutputHighOnPin(GPIO_PORT_P8,GPIO_PIN1);
}

跑马灯

思路:通过空循环实现延时,时间和主频有关,每次延时上一个灯灭,下一个灯亮;值得注意的是需要关闭看门狗。

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
#include <msp430f5529.h>
void InitIo()
{
P8DIR |= BIT1;
P3DIR |= BIT7;
P7DIR |= BIT4;
P6DIR |= BIT3;
P6DIR |= BIT4;
P3DIR |= BIT5;
}

int main(void)
{
WDTCTL = WDTPW | WDTHOLD;
InitIo();
int i = 0;
P8OUT |= BIT1;
while(1){
for(i=0;i<5000;i++) ;
P8OUT &=~ BIT1;
P3OUT |= BIT7;
for(i=0;i<5000;i++) ;
P3OUT &=~ BIT7;
P7OUT |= BIT4;
for(i=0;i<5000;i++) ;
P7OUT &=~ BIT4;
P6OUT |= BIT3;
for(i=0;i<5000;i++) ;
P6OUT &=~ BIT3;
P6OUT |= BIT4;
for(i=0;i<5000;i++) ;
P6OUT &=~ BIT4;
P3OUT |= BIT5;
for(i=0;i<5000;i++) ;
P3OUT &=~ BIT5;
P8OUT |= BIT1;
}
return 0;
}

中断

有关中断的知识,我在之前一篇博文已经提过,故不赘述。

实现现象:当S1按键被按下松开后,LED1灯状态翻转。

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
#include "driverlib.h"
#include "msp430.h"

void InitTo()
{
P8DIR |= BIT1;//设置P8.1为输出
P1DIR &=~ BIT2; //设置P1.2为输入
P1REN = BIT2; //设置上拉电阻
P1OUT = BIT2;

P1IE = BIT2;//允许P1.2中断
P1IES |= BIT2; //下降沿中断

}

int main(void)
{
WDTCTL = WDTPW | WDTHOLD; //关闭看门狗
InitTo();
_enable_interrupts(); //开启全局中断
while(1)
{
}
}

#pragma vector=PORT1_VECTOR
__interrupt void Port_1_Key(void)//中断函数
{
P1IFG &= ~BIT2;//清除中断状态
P8OUT ^= BIT1;//LED状态翻转
}

作业一

在点亮LED实验的基础上,修改程序,使按下按键一次,LED点亮,再次按下按键,LED熄灭。

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
#include <msp430.h>

void InitTo()
{
P8DIR |= BIT1;//设置P8.1为输出
P8OUT &=~ BIT1;//默认不亮灯
P1DIR &=~ BIT2; //设置P1.2为输入
P1REN = BIT2; //设置上拉电阻
P1OUT = BIT2;
}

int main(void)
{
WDTCTL = WDTPW | WDTHOLD; //关闭看门狗
InitTo();
while(1)
{
if (P1IN&BIT2) {
__delay_cycles(1); //空循环
}
else {
P8OUT ^= BIT1;
__delay_cycles(500000); //消除按键抖动
}
}
}

作业二

使用GPIO中断实现按键控制跑马灯:按下一个按钮,跑马灯开始;按下另一个按键,跑马灯停止

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
#include "driverlib.h"
#include "msp430.h"
int flag = 0;
void InitTo()
{
P8DIR |= BIT1;//设置LED灯
P3DIR |= BIT7;
P7DIR |= BIT4;
P6DIR |= BIT3;
P6DIR |= BIT4;
P3DIR |= BIT5;

P1DIR &=~ BIT2; //设置P1.2为输入
P1REN = BIT2; //设置上拉电阻
P1OUT = BIT2;
P2DIR &=~ BIT3; //设置P2.3为输入
P2REN = BIT3; //设置上拉电阻
P2OUT = BIT3;

P1IE = BIT2;//允许P1.2中断
P1IES |= BIT2; //下降沿中断
P2IE = BIT3;//允许P2.3中断
P2IES |= BIT3; //下降沿中断

}

int main(void)
{
WDTCTL = WDTPW | WDTHOLD; //关闭看门狗
InitTo();
_enable_interrupts(); //开启全局中断
while(1)
{
if(flag==1){
P3OUT &=~ BIT5;
P8OUT |= BIT1;
_delay_cycles(500000);//延时500毫秒
}
if (flag==1){
P8OUT &=~ BIT1;
P3OUT |= BIT7;
_delay_cycles(500000);//延时500毫秒
}
if (flag==1){
P3OUT &=~ BIT7;
P7OUT |= BIT4;
_delay_cycles(500000);//延时500毫秒
}
if (flag==1){
P7OUT &=~ BIT4;
P6OUT |= BIT3;
_delay_cycles(500000);//延时500毫秒
}
if (flag==1){
P6OUT &=~ BIT3;
P6OUT |= BIT4;
_delay_cycles(500000);//延时500毫秒
}
if (flag==1){
P6OUT &=~ BIT4;
P3OUT |= BIT5;
_delay_cycles(500000);//延时500毫秒
}
}
}

#pragma vector=PORT1_VECTOR
__interrupt void Port_1_Key(void)
{
P1IFG &= ~BIT2;//清除中断状态
flag = 1;
_delay_cycles(50000);//消除抖动
}

#pragma vector=PORT2_VECTOR
__interrupt void Port_2_Key(void)//中断函数
{
P2IFG &= ~BIT3;//清除中断状态
flag = 0;
_delay_cycles(50000);//消除抖动
}

思考与分析

MSP430的IO口都具备哪些功能?

指导书p16

端口 功能
P1 P2 I/O 中断 片内外设功能
P3 ~ P11 I/O 片内外设功能
PJ I/O JTAG功能复用
S COM I/O 驱动液晶

与IO口相关的寄存器有哪些?

指导书p17-18

寄存器 功能
PxDIR 输入/输出方向寄存器
PxIN 输入寄存器
PxOUT 输出寄存器
PxREN 上/下拉电阻使能寄存器
PxSEL 功能选择寄存器
PxDS 输出驱动强度寄存器
PxIE 中断使能寄存器
PxIES 中断触发沿选择寄存器
PxIFG 中断标志寄存器

如何去掉机械按钮产生的毛刺、抖动等现象?

  1. 使用按位与P1IFG&(~P1DIR),将输出IO排除,防止双键按下
  2. 延时,消除前面的下降沿
  3. 检测到后部下降沿后再延时,再检查电平 P1IN&(Push_Key)==0
  4. 用PIIFG滤除IO影响后的Push_Key

去掉关闭看门狗的代码,程序能否正常运行,为什么?

不能,系统默认看门狗是开启,这样就必须不断喂狗,否则程序会自动复位。

参考资料

  1. MSP430单片机GPIO编程入门教程
  2. Hexadecimal and Binary Number System basics for Embedded Programming
  3. Tutorial : Embedded programming basics in C – bitwise operations

本文作者: rhinoc

本文链接: https://www.rhinoc.top/msp_3/

版权声明: 本博客所有文章除特别声明外,均采用BY-NC-SA 4.0国际许可协议,转载请注明。

打赏
Love U 3000
  • Through WeChat
  • Through Alipay
0%