我想知道当我们向GPIO写“0”时会发生什么(实际意图是拉下输出)。
我不确定控制器是否会将GPIO引脚拉低并将其内部连接到地,或者只是在内部断开引脚,并使其与微控制器连接的外设(LED)断开连接。
我的实际任务是:
我必须从4个gpio引脚发送8位数据(Ex PORTA4-7)。所以要做到这一点,我必须写高位(D4-D7)然后(D0-D3)。
我的方法是:
% Writing the higher bits first
PORTA=PORTA|(DATA & 0xF0);
%Writing the lower bits
PORTA=PORTA|((DATA & 0x0F)<<4);
主要疑问是“这段代码是否会干扰剩余的GPIO(PORTA0-3)”。因为我将它们连接到4个ADC输入。
答案 0 :(得分:3)
了解GPIO如何耦合在一起的最佳方法是访问数据表。 TI的MSP430数据表就是一个很好的例子。
输入/输出部分非常明确地说明了GPIO寄存器如何与IO焊盘本身进行交互。这是端口P1.0-P.17(来自上面数据表的第80页)。
<强>输出强>
这里的基本要点是:
这是一个简单的简化版本:
<强>输入强>
同样,这里是检查在“输入”模式下使用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 Pads并不像它们看起来那么简单,您应该始终访问数据表以了解它是多么糟糕/微妙/混淆/等等。
例如,在上面的TI示例中,以下危险适用于您的原始问题:
(而P1DIR.x = 0)
P1REN.x + P1OUT.x
当然,IO pad拓扑是特定于MCU的。在推进项目之前,我建议您查看数据表中的IO-Pad拓扑。它应该是你最好的朋友。
代码惯例
尽可能考虑使用| =,&amp; =和^ =运算符,例如:
P1OUT |= (1<<2)+(1<<3) //assert pin2 & pin3 high
如果不能,请考虑使用压缩结构或经过单元测试的封装例程:
struct myporta {
uint b3_0 : 4; //use unsigned int-type
uint b4 : 1;
uint b5_10 : 6;
uint b25_b11 : 15;
uint b26 : 1;
uint b31_27 : 5;
} __attribute__ ((packed)); //gcc syntax
...
//write to my LED
myporta *porta = &PORTA; //if you w
porta->b26 = 1; //turn the led on
没有什么比gpio互相破坏更糟糕了!
答案 1 :(得分:1)
MCU将主动驱动引脚为低电平,您可以将其视为接地引脚more info here。
PORTA=PORTA|(DATA & 0xF0);
这不会影响4个下部引脚,但仍然不正确。如果PORTA已设置为高电平且数据包含零,则不会将引脚驱动为低电平。你想掩盖DATA的相关部分,你只想保留你没有改变的PORTA部分:
PORTA = (PORTA & 0x0F) | (DATA & 0xF0);
然后类似地设置4 lsb:
PORTA = (PORTA & 0xF0) | (DATA & 0x0F);
答案 2 :(得分:1)
是的,写入PORTA会干扰所有位,即使其中一些是DDRA的指定输入。
你必须确保在低位读取ADC读数时不要写高位。
甚至像
这样的东西% Writing the higher bits first
PORTA=PORTA|(DATA & 0xF0);
%Writing the lower bits
PORTA=PORTA|((DATA & 0x0F)<<4);
不起作用。读取右侧的PORTA将为其引脚提供一些值,即0或1,即使电压介于两者之间。然后将该值写入同一引脚,暂时将其驱动为高电平或低电平。