Attiny25 奇怪的时机/行为

Attiny25 weird timing/behaviour

提问人:Gambanishu Habbeba 提问时间:6/3/2022 最后编辑:Gambanishu Habbeba 更新时间:6/3/2022 访问量:71

问:

项目如下:一个 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 的数据,第三行是距离。Bad timing

如果我在打开MOSFET后添加一行,如下所示:

...
                setOutput(signalPin);
                setLow(signalPin);

                MOSFETPowerOn(devPower)

                ping(debug)
                initSleep(1<<WDP2);

                measureDHT();
...

...发生以下情况:Correct timing

在底线中,您会看到“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,这个简化版本和原始代码都可以正常工作。那么,这里到底有什么样的疯狂呢?这是电子问题还是编码/编译问题?

C 微控制器 AVR Attiny

评论

1赞 user253751 6/3/2022
您是否尝试过通过删除代码中所有不相关的部分来创建一个最小的测试用例,直到问题消失?
0赞 Lundin 6/3/2022
是什么类型?请张贴声明。并避免全球意大利面条编程......buff
0赞 Lundin 6/3/2022
“如果我添加一行随机代码,我的整个程序会突然改变其行为”几乎总是由堆栈溢出或类似的内存损坏错误引起的。
0赞 Gambanishu Habbeba 6/3/2022
最小的测试用例见编辑。 buff 是全球意大利面吗?我需要几个变量来保存一些数据。while 的事情是关于收集这 12 个字节并将其发送到某个地方。另外,关于添加随机代码:我正在调试是否通过添加我可以监控或用于触发范围的东西。我发现在这个过程中,它神奇地解决了这个问题。看看我编辑中的示例。那里没有意大利面或随机代码,问题仍然是一样的。那里不太可能出现堆栈溢出。volatile uint8_t buff[12]
0赞 user253751 6/3/2022
这个引脚更改中断是什么?

答: 暂无答案