在4位数据模式下,是否可以将其他4位用于其他内容?

问题描述 投票:0回答:2

因此,我正在编写一个C程序,以便在4位数据模式下连接LCD。但是,我想知道我是否可以使用其他4位来做其他事情,如外部中断。更具体地说,我使用PORTD作为arduino上的数据线但是我还需要引脚PD2来使用INT0中断(按钮)。在我的程序中,我注意到在发送命令时我将低4位设置为0:

PORTD = cmd & 0xf0;
flashLCD();
PORTD = (cmd & 0x0f) << 4;

这很好用,但它将其他位设置为0.这在定时器上调用,这意味着我重复发送命令。因此,我尝试保存寄存器的先前值并使用一些按位操作附加它:

uint8_t initial_state = PORTD;
PORTD = (cmd & 0xf0) | (initial_state & 0x0f);
flashLCD();
PORTD = ((cmd & 0x0f) << 4) | (initial_state & 0x0f)

它在LCD上发送cmd,但它仍然不会响应中断。我想知道是否有些东西我没有考虑到,或者我的逻辑是不正确的。谢谢。

编辑:Nvm我想通了。即使在4位模式下,我的LCD库也会将端口寄存器重置为0,因此其他未使用的端口也会被重置。我只是更改了库,以便在4位模式下可以使用其他端口。

c avr lcd
2个回答
0
投票

您正确地注意到可以使用按位运算保留其他位

PORTD = (PORTD & 0x0F) | (high_bits << 4);

但!这一行将被编译成几个机器指令:

  1. 将PORTD值加载到寄存器中
  2. 在寄存器上执行按位AND
  3. 将high_bits加载到另一个寄存器中
  4. 执行其他计算(高位左移等)
  5. 执行按位OR
  6. 将结果存储回PORTS

让我们想象一下,介于1和6之间的中断触发,它会停止代码执行,并改变PORTD的低位。中断例程完成后,程序继续执行,它将通过中断前寄存器中的内容重写PORTD的所有第8位,从而覆盖PORTD的低位,丢弃中断例程中的所有更改。

因此,有两种方法可以对PORTx原子进行写操作。

第一:在PORTx寄存器更新时禁用中断:

uint8_t old_sreg = SREG; // save SREG register (including I flag)
cli(); // clear I flag, thus prohibiting interrupts
PORTD = (PORTD & 0x0F) | (high_bits << 4); // perform the operation
SREG = old_sreg; // restoring SREG and I flag, if it was set before

第二种方法仅适用于新的AVR内核(例如ATmega328,1284,2560等),但不适用于较旧的AVR内核(ATmega8,32等)。请参考数据表,I / O端口 - >端口作为通用数字I / O - >切换引脚部分。将1写入PINx将反转PORTx的相应位。使用它,可以仅更新PORTx寄存器的所需位,使其他位置保持不变,从而无需锁定中断。它可能在时间关键的环境中很有用,在这种环境中,中断应尽可能快地启动。

PIND = (PORTD ^ (high_bits << 4)) & 0xF0;

当然,如果它保证中断只能改变PORTD的其他(在这个例子中 - 更低)位,它将起作用。如果中断也可以写入相同的位,那么这可能会导致意外的结果,所以,要小心。


0
投票

我不知道Arduino上使用的控制器(ATmega / AVR或其他),你甚至没有指定,你使用哪一个。

但通常,端口和端口引脚可以配置为具有输入或输出模式。由于您通过PORTD提供4位,我假设,整个8位端口(所有端口引脚)都配置为输出。

如果整个端口的某些引脚可以输出引脚而其他引脚可以同时输入引脚,那么您应该考虑手册。

小心切换整个端口的输入/输出,它可能有副作用,例如:不需要的H-L / L-H转换。我有一次使用8255输出芯片,由于液晶显示器的连接复位线导致我的图形LCD复位。

© www.soinside.com 2019 - 2024. All rights reserved.