+
+
Posts List
  1. 实验内容
    1. 调用头文件方法
    2. 固件库配置GPIO方法
    3. 跑马灯
    4. 中断
  2. 作业一
  3. 作业二
  4. 思考与分析
    1. MSP430的IO口都具备哪些功能?
    2. 与IO口相关的寄存器有哪些?
    3. 如何去掉机械按钮产生的毛刺、抖动等现象?
    4. 去掉关闭看门狗的代码,程序能否正常运行,为什么?
  5. 参考资料

电工实习(一)基础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