Hi I'm using Watchdog to control LED lights. the microcontroller is connected to laptop with a cable. Input to the microcontroller is 5V. now on the pins there is one pin PB2
which is 5V
directly connected to the input. I want to do that if I remove that 5V female-to-male wire from PB2
the LED turn off. when I plug in again with PB2
it the light turn on after that the watchdog called and turn red light off after every 4 sec
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#define WDTO_4S 8
void fun_red(){
PORTB.IN=0x04; // PB2 as input
PORTB.DIR=0x09; // PB0 and PB3 output
PORTB.OUTCLR=0x00; // Green
PORTB.OUTSET=0x01;
wdt_enable(WDTO_4S);
do
{
if (PORTB.IN)
{
PORTB.OUTCLR=0x00; // red
}
else{
PORTB.OUTSET=0x08;
}
} while(1);
wdt_reset();
}
int main(void)
{
fun_red();
}
OK, so in the edit it seems that you are wish to use PB2 as an input to control the LED on PB3 - is that correct?
You should not think in terms of voltages, these are digital I/O they have a high state and a low state and a threshold between the two. The inputs on your part will go high at anything above 0.8 volts. However removing the input voltage by disconnecting the wire will have no effect if you have enabled the internal pull-up, and if you have not, it will float and may not trigger a logic 0 (zero).
You either need an external pull-down resistor, or you enable the internal pull-up and invert the logic - i.e. LED on when the input is low, and LED off when input is high. Then instead of connecting PB2 to 5V you connect it to GND. Removing the GND connection will cause the logic state to become 1 because of the internal-pull up. Moreover this is much safer as it avoids any risk of applying excessive voltage to the input and damaging the processor.
Given your apparent lack of knowledge of electronics, I would ask also how you have connected the LED. You should have a current limiting series resistor and have the LED connected the correct way around.
It remains unclear what the purpose of the watchdog is in this. It serves no purpose, but if you enable it you must maintain it to prevent the processor resetting. The purpose of a watchdog is to reset the processor if the software stops running normally by resetting it regularly in the normal software execution path, so if the normal path stops executing the system restarts.
Start by reading this primer App Note: Getting Started with GPIO
First of all, you have misunderstood the function of the GPIO registers. PORTB.IN
reads the input states of the PORTB pins that are configured as input. It is read-only so:
PORTB.IN=0x04; // PB2 as input
has no effect and certainly does not configure the pin as an input. That is done by DDR
, so:
PORTB.DIR=0x09; // PB0 and PB3 output
sets PB0 and PB3 as outputs, and anything that is not an output is an input - so PB2 is an input by virtue of this line.
Now if you do as I recommend and use the internal pull-up for PB2, you must enable that in the PIN2CTRL
register:
PORTB.PIN2CTRL = 0x08 ; // PULLUPEN
Incidentally there are symbols defined for all thse bits so you should be able to write:
PORTB.PIN2CTRL = PORT_PULLUPEN_bm ;
which also makes the comment unnecessary.
The registers OUTSET
and OUTCLR
, set (logic 1/high) and clear (logic 0/low) respectively. The pins to be set/clear are determined by a bit mask passed in. As such:
PORTB.OUTCLR=0x00; // Green
does nothing, it sets no pins to the low state. To set the red LED (I am assuming PB3) off and the green LED (PB0) on:
PORTB.OUTCLR = PIN3_bm ;
PORTB.OUTSET = PIN0_bm ;
Now, your test of PORTB.IN
as if it were Boolean will work in this case because you have only one input. But if you have more than one input, it will not distinguish between then, and it is a bad habit in any case to use an integer expression as if it were Boolean. You should explicitly test the state of PB2:
// If PB2 is low (GND wire connected)
if( (PORTB.IN & PIN2_bm) == 0 )
{
PORTB.OUTSET = PIN3_bm ; // red on
}
else
{
PORTB.OUTCLR = PIN3_bm ; // red off
}
The purpose of a watchdog timer is to reset the processor if the software fails to operate normally. You set the timeout, then you need to reset it regularly in the code to prevent a reset. It is not a general purpose you would use for a delay. For that you would use a hardware timer. Unfortunately it gets a little complex; for your board running at 24MHz, the maximum timer period for the 16 bit TIMER1 is about 2.8 seconds. For more flexibility you would normally implement a timer interrupt to count a number of smaller periods and count the number of times the timer reloads. For example:
volatile unsigned tick = 0 ;
ISR (TIMER1_OVF_vect) // Timer1 ISR
{
tick++ ;
}
void tickStart()
{
TCCR1B = (1<<CS11) // Prescaler 24MHz / 8
TCNT1 = 3000 ; // 1 ms at 24MHz/8
TCCR1A = 0x00;
TIMSK = (1 << TOIE1) ; // Enable timer1 overflow interrupt(TOIE1)
sei(); // Enable global interrupts
}
unsigned getTick()
{
unsigned t = 0 ;
do
{
t = tick ;
} while( tick != t ) ;
return t ;
}
Then for a 4 second delay while also monitoring P2 you might do:
// Wait 4 seconds or until PB2 disconnected
unsigned start = getTick() ;
while( getTick() - start < 4000 &&
(PORTB.IN & PIN2_bm) != 0 )
{
// waiting
}
Finally comment your code. It will allow you to understand what you are trying to do and and when you post a question it will tell others what you are trying to do and it it will make your question simpler by having the explanation in-line with the code so it is clear not only what you want the code to do, but how you think it is doing it.
Putting it all together, the following is more plausible:
void fun_red( void )
{
// Initialise I/O
PORTB.PIN2CTRL = PORT_PULLUPEN_bm ;
PORTB.DIR = PIN0_bm | PIN3_bm ;
PORTB.OUTSET = PIN0_bm ; // Green on
for(;;)
{
// Red off
PORTB.OUTCLR = PIN3_bm ;
// Wait for PB2 to be connected (to GND)
while( (PORTB.IN & PIN2_bm) == 0 )
{
// waiting
}
// Red on
PORTB.OUTSET = PIN3_bm ;
// Wait 4 seconds or until PB2 disconnected
unsigned start = getTick() ;
while( getTick() - start < 4000 &&
(PORTB.IN & PIN2_bm) != 0 )
{
// waiting
}
// Wait for PB2 to be reconnected
while( (PORTB.IN & PIN2_bm) != 0)
{
// waiting
}
}
}
int main( void )
{
tickStart() ;
fun_red() ;
}
Remember in this you connect PB2 to GND (0 volts) not not 5V/Vcc. The requirements in the question are not entirely clear but what this will do (untested - I don't have the hardware) is:
While it is not its intended purpose and it is not really useful for general purpose, because this requirement is very simple it is possible to us the watchdog timer to implement the desired behaviour as follows:
void fun_red()
{
// Initialise I/O
PORTB.PIN2CTRL = PORT_PULLUPEN_bm ;
PORTB.DIR = PIN0_bm | PIN3_bm ;
// Green on
PORTB.OUTSET = PIN0_bm ;
// Red off
PORTB.OUTCLR = PIN3_bm ;
// Enable watchdog
wdt_enable(WDTO_4S);
for(;;)
{
// Maintain watchdog while waiting for
// PB2 to be connected (to GND)
while( (PORTB.IN & PIN2_bm) == 0 )
{
wdt_reset() ;
}
// Red on
PORTB.OUTSET = PIN3_bm ;
// Maintain watchdog while waiting for
// PB2 to be disconnected (from GND)
while( (PORTB.IN & PIN2_bm) != 0)
{
wdt_reset() ;
}
// Red off
PORTB.OUTCLR = PIN3_bm ;
// Wait for PB2 to be reconnected (to GND)
// without maintaining watchdog. Will reset after 4 seconds
// if not reconnected.
while( (PORTB.IN & PIN2_bm) != 0)
{
// do nothing
}
}
}
Here after PB2 is disconnected, the watchdog is not maintained, so that after 4 seconds a reset will occur and it with restart the program and wait for PB2 to be connected. I think I should class such code as a "dirty-trick", not something to be considered normal or particularly useful.