Necesito detectar si se ha presionado un interruptor durante más tiempo que el establecido, sin usar ningún registro de temporizador en mi código incrustado.
Estoy usando el software antirrebote de la siguiente manera para detectar una pulsación normal del interruptor.
int buttonPress (void)
{
static int downCount= 0; // static = value isn't lost between calls.
int currentButton = ((IO0PIN & 0x00000200) == 0x00000200);
if (currentButton ) { // button is down
if (downCount == 5) { // button has been down for 5 counts
downCount++; // increase the count so we don't trigger next time
return 1;
} else { // some count other than 5
if (downCount < 5) // increase if it's less than 5
downCount++;
}
} else { // button is up
downCount = 0;
}
return 0;
}
Sin embargo, me gustaría detectar si este botón se ha presionado durante 5 segundos o más. El problema al que me enfrento es que parece que no puedo contar hasta 300,000 y, si no se alcanza, recurro al original downCount
de 5 para marcar como una pulsación de botón normal.
(Dado que la velocidad de reloj de mi microcontrolador es de 60 MHz, tardará 5 segundos en llegar a 300 000).
He jugado con algo de lógica de la siguiente manera, sin embargo, en el caso que se muestra a continuación, debido a la introducción de la while
declaración, estoy contando hasta 300,000 independientemente de cuánto tiempo se haya presionado el botón.
if (currentButton ) { // button is down
if (downCount == 5) { // button has been down for 5 counts
downCount++; // increase the count so we don't trigger next time
while (downCount > 5) {
if (debounce == 300000) {
flag_5SEC = 1;
} else if (debounce < 300000) {
debounce++;
}
}
return 1;
} else { // some count other than 5
if (downCount < 5) // increase if it's less than 5
downCount++;
}
}
¿Algún consejo o sugerencia sobre cómo realizar esta tarea?
Nota : quiero detectar una pulsación de interruptor más prolongada explícitamente en el código antirrebote anterior, ya que hacer cualquier otra cosa puede tener efectos secundarios adversos en el resto del código, que otra persona había escrito previamente.
Me las arreglé para completar la tarea antes mencionada usando temporizadores, sin embargo, desde entonces, he usado todos los registros de temporizadores (y las resistencias de coincidencia que están disponibles) para tareas más importantes dentro del mismo proyecto.
No necesito detectar un retraso de tiempo preciso, simplemente si el botón ha estado presionado por más de, digamos, 2-3 segundos.
El comentario de @DiBosco aclara aún más:
Entonces, lo que está diciendo es que si presiona un interruptor durante, digamos, veinte conteos y se suelta, actúa como una presión normal que realiza una función, y si se presiona y se mantiene presionado durante dos segundos más o menos, lleva a cabo otra funcion...
Me las arreglé para completar la tarea antes mencionada usando temporizadores, sin embargo, desde entonces, he usado todos los registros de temporizadores (y las resistencias de coincidencia que están disponibles) para tareas más importantes dentro del mismo proyecto.
En ese caso, lo estás haciendo todo mal. A menos que necesite absolutamente la alta resolución, el bajo jitter u otras características de hardware de los temporizadores de hardware, debe realizar su temporización en software, utilizando uno de los temporizadores de hardware para generar interrupciones periódicas continuas que puede contar en el ISR.
Una "interrupción de latido" con un período de entre 100 µs y 100 ms (o más) es una característica común de los sistemas integrados. Esto le permite crear un número arbitrario de temporizadores de software.
Incluso si ya está usando todos los temporizadores de hardware, siempre que al menos uno de ellos esté haciendo algo periódico, como generar una señal PWM o crear un reloj para una interfaz serial, puede habilitar las interrupciones y usarlos. para la base de tiempo de su software. Es posible que el período no sea un valor "conveniente", pero ese es un problema de escala simple que el software puede resolver.
Su código parece estar un poco fuera de lugar, y es difícil de entender realmente, ya que no está claro dónde se encuentra el ciclo while con respecto a la interrupción o lo que sea que establezca la función DownCount.
También parece estar incrementando el contador de rebote en dos lugares en el ciclo while, lo que parece incorrecto.
Su solución en línea es problemática por muchas razones, una de las cuales es que su tiempo variará dependiendo de qué más esté sucediendo en el micro a menos que se detenga y ajuste el ciclo mientras cuenta. Pero detenerse a contar cinco segundos también es una mala idea.
Este tipo de función normalmente se maneja en micros mediante el uso de un contador de pulsos, también conocido como latido del corazón. Básicamente, es una práctica común reservar un temporizador para que actúe como un reloj para su código. El temporizador generaría una interrupción regular, quizás 10 veces por segundo.
Ese controlador de interrupciones puede encargarse de numerosas funciones de mantenimiento, como interruptores antirrebote, LED parpadeantes, verificación de tiempos de espera de comunicación, etc. También puede incluir contar cuánto tiempo se ha presionado un botón. Cuando se ha presionado durante un período de tiempo adecuado, dicho controlador llama al controlador adecuado para ese evento.
Este método le permite usar un solo temporizador para numerosas funciones.
Dado que los botones son operados por humanos muy lentos, en relación con la velocidad del procesador, puede salirse con la suya con un sondeo lento. Cada 10 milisegundos por ejemplo.
Puede crear fácilmente una función para manejar muchos botones, con muchos patrones de presión y acciones de retención.
Una versión muy simple de lo que uso a menudo se ve así. Solo tiene una bandera de retención de 5 segundos, ninguna de las pulsaciones cuenta y reconoce la bandera (las banderas se establecerán inmediatamente después de borrarse nuevamente).
Pero con un poco de creatividad puedes agregar muchas cosas de esta manera. Pero se hará un poco largo.
Incluso puede agregar canales de entrada de la máquina y eliminarlos de esta manera.
#define BUTTON_INTERVAL 10
#define BUTTON_COUNT 1
/* Typedef for a button */
typedef struct button_s {
void* port; /* Use GPIO port type, whatever your platform uses, maybe even via bitbanding */
uint32_t hi_time; /* Time high */
uint8_t pin; /* Pin number */
uint8_t flags; /* Output flags */
} button_t;
/* The array of all buttons */
button_t buttons[BUTTON_COUNT];
/* Handle button polling */
void buttonHandler(void){
uint8_t i;
for(i=0;i<NR_OF_BUTTONS; i++){
button_t *b = buttons[i];
uint8_t state = *b->port & (1<<b->pin);
if(state){
// Saturating unsigned 32-bit addition
// your cpu might have an instruction for this eg: arm __uqadd(a,b))
if(b->hi_time < 0xFFFFFFFF) b->hi_time += BUTTON_INTERVAL;
}else{
b->hi_time = 0;
}
// One of many possible flags comparisons:
if( b->hi_time >= 5000 ){
b->flags |= BUTTON_HI_5S;
}
}
}
/* Example of flag usage */
void waitForButton(){
if( button[0]->flags & BUTTON_HI_5S ){
button[0]->flags &= ~BUTTON_HI_5S;
// ..stuff..
}
}
Los puntos clave son, si va por su cuenta:
- Una estructura para todos los datos, incluso puede reasignar claves sobre la marcha si lo desea.
- Botones infinitos usando estructuras. ¡Nunca vuelvas a escribir este código!
- Temporizadores de saturación, no se desbordan.
- Banderas, fácilmente reemplazables por llamadas al sistema operativo.
Si estoy entendiendo tus necesidades correctamente, quieres algo como esto:
void SwitchCheck(void)
{
DebounceTimer = false; // If using timer flag
if (currentButton)
{
debounce++;
}
else
{
if (debounce > NORMAL_OPERATION)
{
// Do normal stuff here
}
debounce = 0;
}
if (debounce == MAX_TIMEOUT)
{
// Do your held down thing here
}
}
Llame a esto desde su bucle principal. Idealmente, solo llámelo después de haber configurado un bit en una interrupción del temporizador correctamente, para que tenga una sincronización precisa.
He hecho muchas, muchas veces a lo largo de los años cambiar el rebote sin temporizadores (aunque en realidad no es así), simplemente llamando desde el bucle principal y funciona. Sin embargo, si está buscando precisión en su tiempo de cinco segundos, esto no será lo suficientemente bueno.
Edición adicional:
En su temporizador ISR:
TimerISR()
{
DebounceTimer = true;
// Other stuff
}
en principal:
if (DebounceTimer)
SwitchCheck();
O simplemente llámelo desde main sin la verificación de la bandera si no está usando un temporizador y experimente empíricamente con MAX_TIMEOUT.
dibosco
dibosco
rrz0
Trevor_G
rrz0
if(buttonPress())
declaración, que solo es cierta enreturn 1
Trevor_G
rrz0
dibosco
dibosco
nick gammon
millis()
Arduino).rrz0
nick gammon
Thomas Padrón-McCarthy
rrz0