gpt4 book ai didi

c - C 中的状态机 (ATmega)

转载 作者:太空宇宙 更新时间:2023-11-03 23:27:23 29 4
gpt4 key购买 nike

我正在尝试进行数据传输控制。一个带有上拉电阻的按钮连接到 ATmega644P(Slave) 的 PINA3。如果只有总线空闲,我想在按下按钮时发送一些数据。出于测试目的,我使用另一个 ATmega644P(Master)向 Slave 发送数据,这使得总线繁忙。

这就是我想要做的:按下按钮时,启动计时器并等待 300 毫秒。在此期间,如果它接收到一些数据,则进入 bus_not_free 状态。如果总线空闲时计时器达到 300ms,则发送数据。它在总线空闲时工作得很好,但有时,它会在总线繁忙时发送数据。

#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>

#include "uart.h"
#include "bus_free_check.h"
#include "specs.h"

#define F_CPU 4000000UL
#define UART_BAUD_RATE 19200

enum states{
idle_s,
start_timer_s,
wait_s,
bus_check_s,
send_data_s,
bus_not_free_s
};

enum states state=idle_s;

int main(void)
{
DDRA = 0x00; // PORTA is input.
DDRB = 0xFF; // PORTB is output.
DDRC = 0xFF; // PORTC is output.
DDRD = 0b11111010; // PORTD input/output.

PORTA = 0x00;
PORTB = 0x00;
PORTC = 0x00;

TCCR1B = (1 << WGM12);
TIMSK1 = (1 << OCIE1A);

OCR1A = 1171; // 300ms

uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );

sei();

while(1)
{
switch(state)
{
case idle_s:
bus_free=0;
PORTC=0x01;

if (bit_is_clear(PINA,3)) // If the button is pressed
{
while(bit_is_clear(PINA,3)); // Wait until it is unpressed
{
state=start_timer_s; // Start the timer
}
}
else
{
state=idle_s; // Wait in the idle_s until the button is pressed
}

break;

case start_timer_s:
TCCR1B |= (1 << CS10) | (1<< CS12); // Start the timer
state=wait_s; // Go to wait state and wait for 300ms

break;

case wait_s:
if (bit_is_clear(PIND,0)) // During this waiting, if at any time there is a data transfer going on, go to bus_not_free state.
{
TCCR1B &= ~((1 << CS10) | (1 << CS11) | (1 << CS12)); // Stop the timer
TCNT1=0; // Reset the counter
bus_free=0;
state=bus_not_free_s; // Go to bus_not_free state
}

break;

case send_data_s:
send_target_seri_no(); // Bus is free, you can send the data
TCCR1B &= ~((1 << CS10) | (1 << CS11) | (1 << CS12)); // After sending the data, stop the timer.
TCNT1=0; // And reset the counter.
state=idle_s; // Go to idle_s and get ready

break;

case bus_not_free_s:
uart_puts("Bus is not free \r"); // Bus is not free, can't send the data
state=idle_s; // Go to idle state, and don't give up hope

break;

default:
uart_puts("Fatal Error \r");
break;
}
}
}

ISR(TIMER1_COMPA_vect) // If the timer reaches 300ms, that means the bus is free
{
bus_free=1;
if(state==wait_s) // When the timer hits 300ms, if it is still in wait_s state, send the data.
{
state=send_data_s;
}
}

谢谢。

最佳答案

这里有几个问题。其中之一是您的状态机有点关闭。

从空闲状态开始,只有按下按钮才能离开。这是机械按键吗?如果是这样,则需要对其进行去抖动。这意味着,基本上,等待它的状态变得稳定,然后确定是否按下了按钮。来自按钮的虚假输入可能会导致您突然进入和退出空闲状态,从而混淆您和您的程序。

您还稍微滥用了计时器。如果您不想发送任何东西,则不需要打开计时器,因此在完成后将其关闭。您还在等待超时时一遍又一遍地设置计时器。不必要。我很确定定时器功能中的逻辑已关闭。很难说出您打算做什么。

总线检查状态是最大的问题。它做的太多了。退出空闲状态时只需要启动一次定时器。所以把它分成另一个状态。然后,所有检查状态所做的就是在总线空闲时转移到发送状态。您的“三次尝试”循环没有执行任何操作:它不会等待任何更改。

卡在“bus not free”状态的原因是:假设总线输入为 0(不忙)且 bus_free=0。它如何将 bus_free 设置为 1?在这种情况下,您的检查时间功能将关闭计时器,因此 ISR 永远不会触发以更改 bus_free。

关于c - C 中的状态机 (ATmega),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23459835/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com