天南地北客
发表于: 2017-12-22 11:21:40 | 显示全部楼层

在本教程中,我们将一起学习MSP430单片机GPIO的编程方法。本文也适用于Launchpad开发板上使用的MSP430x2xx器件,如MSP430G2553、MSP430G2231等。MSP430单片机上的大多数引脚被分组为最多8个端口, P1到P8。每个端口都是8位宽,并有8个相关的I / O引脚。这些引脚直接映射到相应的端口寄存器,因此可以独立操作I / O引脚。只有端口P1和P2中的引脚支持中断。 此外,每个I / O引脚还具有可配置的上拉和下拉电阻。 每个端口都有一组相关的寄存器,用来操作各个引脚。 位映射和端口分组如下所示:

msp430_pin_mapping.png

msp430_gpio_registers.png

注意:在编程指南/数据手册中使用的引脚的命令约定是'Px.y',其中'x'对应的是端口号(1到8),'y'对应的是引脚号(0到7) X'。例如:P1.1是指端口1的第1引脚,P2.4是指端口2的第4引脚。您将看到与在MSP430 Launchpad开发板上标记引脚相同的约定。


当前版本的MSP430G2 Launchpad使用的是MSP430G2553和MSP430G2452。旧版本(Rev1.4)使用的是MSP430G2231和MSP430G2211。但是,除非另有说明,对于所有支持的器件,编程方法都是一样的。


MSP430单片机的GPIO寄存器

GPIO模块有许多寄存器。我们只会介绍本教程涉及的一些数字I / O寄存器。我将在其他的教程中介绍与中断相关的寄存器(即PxIFGPxIESPxIE)。

1. PxDIR:GPIO方向控制寄存器。将此寄存器中的任何位设置为0将会将相应的引脚[0至7]配置为输入,而将其设置为1将配置为输出。

2. PxIN(只读):用于读取配置为输入的数字I / O引脚的值。 0 =输入为低电平,1 =输入为高电平。

3. PxOUT:当上拉/下拉电阻被禁用时,用于直接将值写入引脚。 0 =输出为低电平,1 =输出为高电平。上拉/下拉电阻使能时:0 =引脚拉低,1 =引脚拉高。

4. RxREN:对于配置为输入的引脚,PxREN用于为给定引脚启用上拉/下拉电阻,PxOUT与PxREN一起用于选择上拉或下拉电阻。将位设置为1将启用相应引脚的上拉/下拉电阻,同时将其设置为0将禁用相同的引脚。

PxDIR
PxREN
PxOUT
I / O配置
0
0
X
输入,禁用电阻
0
1
0
使能内部下拉的输入
0
1
1
使能内部上拉的输入
1
X
X
输出, PxREN无效

5. PxSEL&PxSEL2:由于大多数端口引脚多达4种不同的功能,我们需要一种机制来选择这些功能。这是使用PxSEL和PxSEL2寄存器来实现的。特定引脚的这些寄存器的位组合将选择特定的引脚功能。位组合如下所示:

PxSEL2(第n位)
PxSEL(第n位)
引脚功能
0
0
GPIO(数字I / O)功能
0
1
主要外设功能
1
0
保留。查阅设备特定的数据表。
1
1
辅助外围功能

另请注意,PxSEL / PxSEL2寄存器不会根据模块功能的要求更改引脚方向。确保使用PxDIR寄存器按照复用功能的要求设置正确的引脚方向。


使用C / C ++的MSP430的GPIO编程和示例代码

前提条件:在我们开始编程gpio之前,您需要对C / C ++中的二进制和十六进制系统以及按位运算有基本的了解,下面是两个可以参考的教程(或者如果您已经熟悉这些教程,可以跳过这些教程并继续):

●     嵌入式编程的十六进制和二进制数字系统基础知识

●     教程:嵌入式编程基础C - 位操作


msp430.h是所有MSP430器件的通用头文件。该头文件识别您的器件,并相应地包含器件具体的头文件。每个器件具体的头文件还包括从BIT0到BITF的位定义。其中BITn等于(1 << n),即第n个位的位置是1,其余位是0。


现在让我们看看我们如何给寄存器赋值。我们可以使用十六进制符号和十进制表示法来赋值。如果您的编译器支持其他符号,如二进制符号,也可以使用。比方说,我们要设置Port 1的PIN 6作为输出。它可以通过以下方式完成:

  1. 方式1. P1DIR =(1 << 6); //(二进制左移 - 直接赋值:其他引脚设置为0)
  2. 方式2. P1DIR | = 0x20; //或0x20; (十六进制 - 或分配:其他引脚不受影响)
  3. 方式3.P1DIR | =(1 << 6); //(二进制左移 - 或分配:其他引脚不受影响)
  4. 方式4. P1DIR | = BIT6; //同上,使用标准BIT定义
复制代码

●     在许多情况下,必须避免使用方式1,因为我们直接为寄存器赋值。因此,当我们将P1.6'1'设置为'1'时,其他的被强制分配一个'0',这个'0'可以通过或操作来避免,然后赋值。

●     如果需要批量更改某些位,则可以使用方式2

●     方式3和方式4可以在需要改变某些或者一个位时使用。


这里首先要注意的是,十六进制表示法中前面的零可以被忽略,因为它们没有任何意义,因为我们在这里使用了无符号值(仅为正值),它们被分配给寄存器。 例如。0x4和0x04表示的意思一样。

请注意,位7是最左边的MSB,位0是最右边的LSB,它代表Big Endian格式。 因此,位0是右边的第一位,位1是右边的第二位,依此类推。 BIT和PIN码是基于零的索引值。


使用C / C++的基本示例代码

示例 1)

假设我们希望将端口1的引脚0(即P1.0)配置为输出并希望将其驱动为高电平。可以使用下面的方法:

  1. P1DIR | = BIT0; //与(1 << 0)和0x1相同,将P0.1配置为输出
  2. P1OUT | = BIT0; // P1.0输出高电平
复制代码

示例 2)

将引脚P1.4配置为输出,并单独设置为低电平而不影响其他位,可以通过以下方式:

  1. P1DIR | = BIT4; //将P1.4配置为输出
  2. P1OUT&=〜BIT4; //只有P1.4变低
复制代码

示例3)

将P1.4和P1.6配置为输出并将它们设置为高电平:

  1. P1DIR | = BIT4 | BIT6; //将P1.4和P1.6配置为输出
  2. P1OUT | = BIT4 | BIT6; //驱动P1.4和P1.6的HIGHT
复制代码

示例 4)

配置端口1的所有引脚(P1.0至P1.7)为输出并将其设置为高电平:

  1. P1DIR = 0xFF; //将P1的所有引脚配置为输出
  2. P1OUT = 0xFF; //将所有引脚驱动为高电平
复制代码

示例 5)

在此示例代码中,我们将配置引脚P1.3作为内部上拉的输入:

  1. P1DIR&=〜BIT3; //配置P1.3作为输入(复位后也总是输入)
  2. P1REN = BIT3; //为P1.3启用上拉/下拉
  3. P1OUT = BIT3; //为P1.3选择上拉电阻
复制代码

示例 6)

我们可以检查上面配置的输入引脚P1.3的当前状态,如下所示:

  1. if(P1IN & BIT3)
  2. {
  3.         //P1.3为高电平
  4. }
  5. else
  6. {
  7.         //P1.3为低电平
  8. }
复制代码

示例 7)

假设我们已经配置P1.4作为输入,并且启用上拉电阻,我们要连续扫描P1.4,直到出现一个低电平的引脚。这可以实现如下:

  1. P1DIR &= ~BIT4; //Configure P1.4 as Input
  2. P1REN = BIT4; //Enable Pullup/down for P1.4
  3. P1OUT = BIT4; //Select Pullup resistor for P1.4

  4. if(..)
  5. {
  6.         while( !(P1IN & BIT4) ); //等待,直到P1.4为低电平
  7.         /*do something after loop terminates*/
  8. }
复制代码

跳转到指定楼层
天南地北客
发表于: 2017-12-22 11:42:57 | 显示全部楼层

MSP430单片机GPIO演示例程

注意:下面给出的示例采用的是默认的时钟速度。 我已经在MSP430G2231 / MSP430G2211上使用CCS V6.2.0测试了以下程序,但是它也可以在MSP430G2553 / MSP430G2452和其他兼容的单片机上工作。


Blinky示例代码

GPIO最常见的例子是LED闪烁。 在这里,我们在一个循环中驱动端口1(P1.0)的引脚0为高电平然后为低电平。 P1.0连接到Launchpad开发板上的LED1。 我们将使用内部函数__delay_cycles(unsigned long cycles) 。 显而易见的是,它以参数给出的时钟周期产生延迟时间。 但是,这不是推荐的产生延迟的方法,必须避免使用。 为了简洁起见,我在下面的例子中使用了它。 我们将在另一个教程中看到如何使用Timer来产生精确的延迟。

  1. #include <msp430.h>

  2. int main(void)
  3. {
  4.         WDTCTL = WDTPW | WDTHOLD; //Stop watchdog timer to Prevent PUC Reset
  5.         P1DIR |= BIT0; //Configure P1.0 as Output
  6.         
  7.         while(1)
  8.         {
  9.                 P1OUT ^= BIT0; //Toggle P1.0 - LED Blinks
  10.                 __delay_cycles(400000);
  11.         
  12.                 /* The above code is same as:
  13.                 P1OUT |= BIT0; //Drive P1.0 HIGH - LED1 ON
  14.                 __delay_cycles(400000);

  15.                 P1OUT &= ~BIT0; //Drive P1.0 LOW - LED1 OFF
  16.                 __delay_cycles(400000);        */
  17.         }
  18.         //return 0; //normally this won't execute
  19. }
复制代码

使用按钮开关切换LED

在这个例子程序中,我们将P1.3配置为输入,并在引脚上监视它的低电平。 P.3连接到Launchpad开发板上的按钮开关(S2)。 我们将使用LED2即P1.6作为输出。 最初LED2被点亮。 每当我们按下按钮S2,它将切换LED状态。

  1. #include <msp430.h>

  2. int main(void)
  3. {
  4.         WDTCTL = WDTPW | WDTHOLD; //Stop watchdog timer to Prevent PUC Reset
  5.         P1DIR &= ~BIT3 ; //explicitly making P1.3 as Input - even though by default its Input
  6.         P1REN = BIT3; //Enable Pullup/down
  7.         P1OUT = BIT3; //Select Pullup

  8.         P1DIR |= BIT6; //Configuring P1.6(LED2) as Output
  9.         P1OUT |= BIT6; //drive output HIGH initially

  10.         while(1)
  11.         {
  12.                 if( !(P1IN & BIT3) ) //Evaluates to True for a 'LOW' on P1.3
  13.                 {
  14.                         P1OUT ^= BIT6; //Toggle the state of P1.6
  15.                         while( !(P1IN & BIT3) ); //wait until button is released
  16.                 }
  17.         }
  18.         //return 0; //this won't execute normally
  19. }
复制代码

注意:使用开关作为输入将引起跳动,这是输入的虚假变化,直到开关的触点稳定。 这可以在软件或硬件中使用去抖技术过滤掉。 简单的硬件去抖技术包括带迟滞的RC滤波器(施密特触发器)。


按下按钮时,点亮LED打开,否则熄灭

现在让我们修改上面的例子,当按下按钮时,LED2会发光,释放或不按下时LED不会发光。 当没有按下开关时,内部上拉电阻将强制输入为高电平状态。

  1. #include <msp430.h>

  2. int main(void)
  3. {
  4.         WDTCTL = WDTPW | WDTHOLD; //Stop watchdog timer to Prevent PUC Reset
  5.         P1DIR &= ~BIT3 ; //explicitly making P1.3 as Input - even though by default its Input
  6.         P1REN = BIT3; //Enable Pullup/down
  7.         P1OUT = BIT3; //Select Pullup

  8.         P1DIR |= BIT6; //Configuring P1.6(LED2) as Output
  9.         P1OUT &= ~BIT6; //Turn off LED2 initially
  10.         
  11.         while(1)
  12.         {
  13.                 if( !(P1IN & BIT3) )
  14.                 {
  15.                         P1OUT |= BIT6; //Input LOW - turn led ON
  16.                 }
  17.                 else
  18.                 {
  19.                         P1OUT &= ~BIT6; //Input HIGH - turn led OFF
  20.                 }
  21.         }
  22.         
  23.         //return 0; //normally this won't execute
  24. }
复制代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题 26 | 回复: 45



手机版|

GMT+8, 2024-3-19 17:39 , Processed in 0.090002 second(s), 6 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

快速回复 返回顶部 返回列表