我正在尝试复制包含多功能按钮的耳塞功能。如果您按此按钮 x 次,在一段时间内,耳塞将根据您按按钮的次数执行某些操作。我不知道我是否可以理解(我的母语不是英语,所以如果您评价我的英语就好了)。
这些是我的主要代码和库。
#include <mcu_init.h>
#include <millis.h>
#include <button.h>
int main() {
GPIO_init();
cli();
INT0_init();
TMR0_init();
sei();
while (1) {
handleButton();
}
return 0;
}
#include <millis.h>
static volatile uint32_t miliseconds = 0;
ISR (TIMER0_COMPA_vect) {
miliseconds++;
PORTA |= (1 << 1);
}
uint32_t millis() {
uint32_t time;
uint8_t oldSREG = SREG;
cli();
time = miliseconds;
SREG = oldSREG;
return time;
}
#include <button.h>
volatile uint8_t count = 0;
volatile uint32_t lastPressTime = 0;
ISR (INT0_vect) {
if (millis() - lastPressTime >= 200) {
count++;
lastPressTime = millis();
}
}
void handleButton() {
if (millis() - lastPressTime >= 1500) {
lastPressTime = millis();
switch (count) {
case 2:
PORTA ^= (1 << 1);
count = 0;
break;
case 3:
PORTA ^= (1 << 3);
count = 0;
break;
default:
count = 0;
}
}
return;
}
这些是头文件
#ifndef MILLIS_H_
#define MILLIS_H_
#include <avr/interrupt.h>
uint32_t millis();
#endif
#ifndef BUTTON_H_
#define BUTTON_H_
#include <millis.h>
void handleButton();
#endif
顺便说一句,如果我在 main.c 的 while (1) 内调用 handleButton() 函数之前调用 millis() 函数。它开始工作。但如果我不这样做,定时器 0 中断就不起作用。
我尝试了一切我能做的事情,唯一有效的是:
在 millis.h 中将毫秒声明为 extern volatile uint32_t 并通过 TIMER0 ISR 递增该变量。我使用这个变量作为我的 millis()。
在我的 main.c 的 while (1) 内调用 handleButton() 函数之前调用 millis() 函数。在这种情况下,我不明白为什么会发生这种情况,以及是否真的有必要在主循环中执行此调用。
在你的handleButton函数中,每次进入if()块时都会重置count变量。
如果您不使用 millis() 函数,即在每个主循环中执行 switch(),一旦中断例程将其从零递增并返回,计数变量可能会再次重置为零。
如果你想在超时发生后重置变量计数并且不再按第一次发生,你需要处理一些状态,如下面的代码:
// as in your code, the minimum acceptable time between press events
#define def_click_debounce_ms 200
// after a press event occurs, if no more press events occur after this time, we assume that the user press sequence has completed
#define def_pause_validate_click_ms (def_click_debounce_ms + 1000)
// your ISR for the press event, just enriched with a signal on too short press
ISR (INT0_vect) {
if (millis() - lastPressTime >= def_click_debounce_ms) {
// increment the number of press detected
count++;
lastPressTime = millis();
}
else
{
// signal to main that an invalid press happened
reset_wait_release_request++;
}
}
// the status of handleButton check
typedef enum _enum_check_button_press_status
{
enum_check_button_press_status_init = 0,
enum_check_button_press_status_check_press_sequence,
enum_check_button_press_status_numof
}enum_check_button_press_status;
// our check button press status variable
enum_check_button_press_status e_check_button_press_status = enum_check_button_press_status_init;
// we use this variable to keep the number of press events handleButton detects
uint8_t num_consecutive_press_detected = 0;
void handleButton() {
// store the current time
const uint32_t now_ms = millis();
switch(e_check_button_press_status)
{
case enum_check_button_press_status_init:
default:
{
// no press detected at this moment
num_consecutive_press_detected = 0;
// check for a press sequence
e_check_button_press_status = enum_check_button_press_status_check_press_sequence;
break;
}
case enum_check_button_press_status_check_press_sequence:
{
// has the interrupt routine detected a new press?
if (count != main_count)
{
// align our own press counter
main_count = count;
// increment the number of press detected by the main
num_consecutive_press_detected++;
// mark the time of the last press detected by the main
start_wait_release_ms = now_ms;
}
// if an invalid press happened, let's restart our release timer
else if (reset_wait_release_request != reset_wait_release_ack)
{
reset_wait_release_ack = reset_wait_release_request;
// we restart the time of the last press detected by the main
start_wait_release_ms = now_ms;
}
// if a timeout happens waiting for next press, let's check if it was a valid press sequence
else if ((num_consecutive_press_detected > 0) && (now_ms - start_wait_release_ms >= def_pause_validate_click_ms))
{
// do your stuff
switch(num_consecutive_press_detected)
{
case 0:
{
// should never happen...
break;
}
case 2:
{
// do the 2-clicks stuff
PORTA ^= (1 << 1);
break;
}
case 3:
{
// do the 3-clicks stuff
PORTA ^= (1 << 3);
break;
}
case 1:
default:
{
printf("Invalid number of press detected: %u\n", (unsigned int)num_consecutive_press_detected);
break;
}
}
// go back to the init state
e_check_button_press_status = enum_check_button_press_status_init;
}
break;
}
}
}