提问人:Gambanishu Habbeba 提问时间:6/3/2022 最后编辑:Gambanishu Habbeba 更新时间:6/3/2022 访问量:71
Attiny25 奇怪的时机/行为
Attiny25 weird timing/behaviour
问:
项目如下:一个 attiny25 为 dht22 和一个带有 MOSFET 的 unltrasonic 距离传感器供电。MOSFET的输出也用于为总线供电,其上有一个3.3K上拉电阻。主程序大部分时间都处于休眠状态,当它需要时,它会执行以下命令:
if ((buff[1]<<8) + buff[0] <= powerCutoff) {
generalStatus &= wipeMask; // Wipe lower 3 bits
setOutput(signalPin);
setLow(signalPin);
MOSFETPowerOn(devPower)
initSleep(1<<WDP2);
measureDHT();
measureDistance();
// sendData();
MOSFETPowerOff(devPower)
}
您还需要了解以下内容:
#define MOSFETPowerOn(line) { line ## _port &= ~(1<<line); line ## _ddr |= (1<<line); asm("nop"); }
#define MOSFETPowerOff(line) { line ## _ddr &= ~(1<<line); line ## _port |= (1<<line); asm("nop"); }
#define ping(bit) { \
bit ## _port &= ~(1<<bit); \
bit ## _ddr |= (1<<bit); \
bit ## _port |= (1<<bit); \
asm("nop"); \
bit ## _port &= ~(1<<bit); \
asm("nop"); }
/** Devices power pin */
#define devPower PB2
#define devPower_port PORTB
#define devPower_ddr DDRB
#define devPower_pin PINB
/** Debug */
#define debug PB0
#define debug_port PORTB
#define debug_ddr DDRB
#define debug_pin PINB
void initSleep(uint8_t timing) {
asm("WDR");
WDTCR = 1<<WDIE | timing;
MCUCR &= ~(1<<SM0);
MCUCR |= 1<<SE | 1<<SM1;
asm("sleep");
}
void measureDHT() {
generalStatus |= 1<<fDHTMeasurementInProgress;
initSleep(1<<WDP2); // 0.25s
for (uint8_t i = 2; i < 7; i++) buff[i] = 0;
dht22_status.status = dht22_inPresence;
dht22_status.bitCounter = 0;
dht22_status.byteCounter = 0;
setOutput(devBus);
_delay_us(1200); // 1ms initial low pulse
setInput(devBus);
_delay_us(50);
...
时钟为8MHz。电源来自调节器,是的,有一个小上限。我将这段代码的一部分用于许多其他项目,例如initSleep(),它工作正常。
问题是在打开 dht 的电源和用它启动通信之间会发生什么。如数据表所示,看门狗定时器的 1<<WDP2 提供 0.25s 的休眠时间。然后 measureDHT() 启动,(几乎)以相同的 0.25 秒睡眠开始,然后我把公共汽车开得很低。因此,在通电和将总线驱动到低电平之间,人们预计会超过 500 毫秒。现实是 2349 毫秒。 :(其余的时机都很好。第一行是功率,第二行是来自 dht 的数据,第三行是距离。
如果我在打开MOSFET后添加一行,如下所示:
...
setOutput(signalPin);
setLow(signalPin);
MOSFETPowerOn(devPower)
ping(debug)
initSleep(1<<WDP2);
measureDHT();
...
在底线中,您会看到“ping”是一个小尖峰。时机突然正确了。我不知道它可能是什么。我使用的是 Linux,我的 avr-gcc 是 v5.4.0,程序员是 AVR Dragon。有什么想法吗?
编辑: 如果我将代码减少为:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdint.h>
#include "macros.inc"
#include "pinConfig.h"
#define wakeCycle GPIOR0
#define MOSFETPowerOn(line) { line ## _port &= ~(1<<line); line ## _ddr |= (1<<line); asm("nop"); }
#define MOSFETPowerOff(line) { line ## _ddr &= ~(1<<line); line ## _port |= (1<<line); asm("nop"); }
void initSleep(uint8_t timing) {
asm("WDR");
WDTCR = 1<<WDIE | timing;
MCUCR &= ~(1<<SM0);
MCUCR |= 1<<SE | 1<<SM1;
asm("sleep");
}
// Watchdog timeout ISR
ISR(WDT_vect) {
wakeCycle = 12;
}
void measureDHT() {
initSleep(1<<WDP2); // 0.25s
setOutput(devBus);
_delay_us(1200); // 1ms initial low pulse
setInput(devBus);
_delay_us(50);
}
int main(void) {
MOSFETPowerOff(devPower) // MOSFET driven device turned off by pullup resistor
GIMSK |= 1<<PCIE; // Enable pin change interrupt
sei();
while (1) {
MOSFETPowerOn(devPower)
initSleep(1<<WDP2);
measureDHT();
MOSFETPowerOff(devPower)
initSleep(1<<WDP2 | 1<<WDP1 | 1<<WDP0); // 2 sec
}
}
问题仍然是一样的。如果我将看门狗干扰器更改为:
// Watchdog timeout ISR
ISR(WDT_vect) {
asm("nop");
}
它工作正常。我从电路中删除了 DHT,这个简化版本和原始代码都可以正常工作。那么,这里到底有什么样的疯狂呢?这是电子问题还是编码/编译问题?
答: 暂无答案
评论
buff
volatile uint8_t buff[12]