Embedded 当我们将0写入GPIO时会发生什么

Embedded 当我们将0写入GPIO时会发生什么,embedded,avr,gpio,Embedded,Avr,Gpio,我想知道当我们将“0”写入GPIO时会发生什么情况(实际的目的是拉低输出) 我不确定控制器是否拉下GPIO引脚并将其内部连接至接地,或者它只是在内部断开该引脚并使其与微控制器连接的外围设备(LED)断开 我的实际任务是: 我必须从4个gpio引脚(例如PORTA4-7)发送8位数据。所以要做到这一点,我必须先写高位(D4-D7),然后再写(D0-D3) 我的做法是: % Writing the higher bits first PORTA=PORTA|(DATA & 0xF0); %

我想知道当我们将“0”写入GPIO时会发生什么情况(实际的目的是拉低输出)

我不确定控制器是否拉下GPIO引脚并将其内部连接至接地,或者它只是在内部断开该引脚并使其与微控制器连接的外围设备(LED)断开

我的实际任务是:

我必须从4个gpio引脚(例如PORTA4-7)发送8位数据。所以要做到这一点,我必须先写高位(D4-D7),然后再写(D0-D3)

我的做法是:

% Writing the higher bits first
PORTA=PORTA|(DATA & 0xF0);

%Writing the lower bits
PORTA=PORTA|((DATA & 0x0F)<<4);
%先写入高位
PORTA=PORTA |(数据&0xF0);
%写入低位

PORTA=PORTA |((DATA&0x0F)MCU将主动驱动引脚降低,您可以将其视为引脚接地

这不会影响4个较低的管脚,但仍然不正确。如果PORTA已设置为高且数据包含零,则不会将管脚设置为低。您希望屏蔽数据的相关部分,并且只希望保留PORTA中未更改的部分:

PORTA = (PORTA & 0x0F) | (DATA & 0xF0);
然后类似地设置4 lsb:

PORTA = (PORTA & 0xF0) | (DATA & 0x0F);

MCU将主动驱动引脚降低,您可以将其视为引脚接地

这不会影响4个较低的管脚,但仍然不正确。如果PORTA已设置为高且数据包含零,则不会将管脚设置为低。您希望屏蔽数据的相关部分,并且只希望保留PORTA中未更改的部分:

PORTA = (PORTA & 0x0F) | (DATA & 0xF0);
然后类似地设置4 lsb:

PORTA = (PORTA & 0xF0) | (DATA & 0x0F);

是的,写入PORTA将干扰所有位,即使其中一些位是DDRA指定的输入

在读取低位的ADC读数时,必须确保没有写入高位

甚至像

% Writing the higher bits first
PORTA=PORTA|(DATA & 0xF0);

%Writing the lower bits
PORTA=PORTA|((DATA & 0x0F)<<4);
%先写入高位
PORTA=PORTA |(数据&0xF0);
%写入低位

PORTA=PORTA |((DATA&0x0F)是,写入PORTA将干扰所有位,即使其中一些位是DDRA指定的输入

在读取低位的ADC读数时,必须确保没有写入高位

甚至像

% Writing the higher bits first
PORTA=PORTA|(DATA & 0xF0);

%Writing the lower bits
PORTA=PORTA|((DATA & 0x0F)<<4);
%先写入高位
PORTA=PORTA |(数据&0xF0);
%写入低位

PORTA=PORTA |((DATA&0x0F)了解GPIO是如何耦合在一起的最好方法就是访问数据表。TI的MSP430数据表就是一个很好的例子

输入/输出部分对GPIO寄存器如何与IO焊盘交互进行了非常明确的说明。以下是端口P1.0-p.17(来自上面数据表的第80页)

输出

这里给你的基本收获是:

  • 如果IO焊盘处于输出模式,则将“0”写入P1OUT.x(例如,位0为P1OUT.0)将使输出变低
下面是一个更简单的简化版本:

输入

同样,这里是在“输入”模式下使用IO板的检查

这里的基本要点是写入P1OUT.x对输出没有影响;输出缓冲区是三态的

危险

如果你的程序在几个任务中共享一个GPIO端口登记器,那么你必须确保对这个登记器的访问是“强>线程安全< /强>。对于嵌入式系统,这通常意味着确保ISR不要把事情搞砸。”

//... (from main thread)
P1OUT = P1OUT | 0x02;

//... (from some ISR)
P1OUT = P1OUT | 0x01;
这通常转化为以下内容:

//... (from main thread)
mov  P1OUT,  %some_reg
operate on %some_reg
mov   %some_reg, P1OUT

//... (from some ISR)
mov  P1OUT,  %some_reg
operate on %some_reg
mov   %some_reg, P1OUT

//and then the time series looks like   (P1OUT = 0 initially)
[0]:  mov P1OUT,  %some_reg_main_thread  (%reg_m = 0)
[1]:  or  0x02,   %some_reg_main_thread  (%reg_m = 2)
[2]:  ISR fires!
[3]:  mov P1OUT,  %some_reg_isr_thread   (%reg_i = 0)
[4]:  or  0x01,   %some_reg_isr_thread   (%reg_i = 1)
[5]:  mov %some_reg_isr_thread, P1OUT    (P1OUT  = 1)
[6]:  ISR exits
[7]:  mov %some_reg_main_thread, P1OUT   (P1OUT  = 2)

(end result: P1OUT=2, but should be 3 (0x01 | 0x02))
此外,IO板并不像看上去那么简单,你应该经常查看数据表,了解它到底有多糟糕/微妙/混乱/等等

例如,在上面的TI示例中,以下危险适用于您的原始问题:

(当P1DIR.x=0时)

  • P1REN.x+P1OUT.x

    • 如果P1REN.x为“1”,并且您切换P1OUT.x,这也会切换上拉电阻器的开和关

当然,IO pad拓扑是特定于MCU的。我建议在继续您的项目之前,先查看数据表中的IO pad拓扑。它应该是您最好的朋友

代码实践

如果可以,请考虑使用|=、&=和^=运算符,例如:

P1OUT |= (1<<2)+(1<<3)   //assert pin2 & pin3 high

没有什么比gpio互相碰撞更糟糕的了!

了解gpio是如何耦合在一起的最好方法就是访问数据表。TI的MSP430数据表就是一个很好的例子

输入/输出部分对GPIO寄存器如何与IO焊盘交互进行了非常明确的说明。以下是端口P1.0-p.17(来自上面数据表的第80页)

输出

这里给你的基本收获是:

  • 如果IO焊盘处于输出模式,则将“0”写入P1OUT.x(例如,位0为P1OUT.0)将使输出变低
下面是一个更简单的简化版本:

输入

同样,这里是在“输入”模式下使用IO板的检查

这里的基本要点是写入P1OUT.x对输出没有影响;输出缓冲区是三态的

危险

如果你的程序在几个任务中共享一个GPIO端口登记器,那么你必须确保对这个登记器的访问是“强>线程安全< /强>。对于嵌入式系统,这通常意味着确保ISR不要把事情搞砸。”

//... (from main thread)
P1OUT = P1OUT | 0x02;

//... (from some ISR)
P1OUT = P1OUT | 0x01;
这通常转化为以下内容:

//... (from main thread)
mov  P1OUT,  %some_reg
operate on %some_reg
mov   %some_reg, P1OUT

//... (from some ISR)
mov  P1OUT,  %some_reg
operate on %some_reg
mov   %some_reg, P1OUT

//and then the time series looks like   (P1OUT = 0 initially)
[0]:  mov P1OUT,  %some_reg_main_thread  (%reg_m = 0)
[1]:  or  0x02,   %some_reg_main_thread  (%reg_m = 2)
[2]:  ISR fires!
[3]:  mov P1OUT,  %some_reg_isr_thread   (%reg_i = 0)
[4]:  or  0x01,   %some_reg_isr_thread   (%reg_i = 1)
[5]:  mov %some_reg_isr_thread, P1OUT    (P1OUT  = 1)
[6]:  ISR exits
[7]:  mov %some_reg_main_thread, P1OUT   (P1OUT  = 2)

(end result: P1OUT=2, but should be 3 (0x01 | 0x02))
此外,IO板并不像看上去那么简单,你应该经常查看数据表,了解它到底有多糟糕/微妙/混乱/等等

例如,在上面的TI示例中,以下危险适用于您的原始问题:

(当P1DIR.x=0时)

  • P1REN.x+P1OUT.x

    • 如果P1REN.x为“1”,并且您切换P1OUT.x,这也会切换上拉电阻器的开和关