How to change LED flashing pattern by sw - c

I currently use PIC16F1827 to tact sw to led blinking pattern
We are creating a program to switch.
The input of sw is RA0, and when you press the button, it drops to Low.
In creating the program There is one problem.
For example, press sw while processing pat1 ();
There are times when I want to switch to the next lighting mode.
However, until the processing of pat1 (); is finished, the blinking pattern
It will not switch.
Is there a way to switch the flashing pattern at the moment you press sw?
Thank you.
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#define _XTAL_FREQ 4000000
/*
* CONFIG will be omitted
*/
void internal_osc();
void io_int();
void tmr0_int();
void sw_scan();
void pat1();
void pat2();
void pat3();
void pat4();
char tmr0_cnt;
char sw_data;
char SwStatus;
char cnt;
void main(void){
internal_osc();
io_int();
tmr0_int();
while(1){
//sw_scan();
switch(sw_data){
case 1 :
pat1();
break;
case 2 :
pat2();
break;
case 3 :
pat3();
break;
case 4 :
pat4();
break;
default :
PORTB = 0x00;
break;
}
}
}
void interrupt ISR(void){
INTCONbits.TMR0IF = 0;
TMR0 = 130;
cnt++;
if(cnt>=15){
cnt=0;
sw_scan();
}
}
void internal_osc(void){
OSCCON = 0x6a;
}
void io_int(void){
TRISA = 0x01;
TRISB = 0x00;
ANSELA = 0x00;
ANSELB = 0x00;
}
void tmr0_int(void){
OPTION_REG = 0x82;
TMR0 = 130;
INTCONbits.TMR0IE = 1;
INTCONbits.GIE = 1;
}
void sw_scan(void){
if(PORTAbits.RA0 == 0){
__delay_ms(10);
if(PORTAbits.RA0 == 0){
if(SwStatus==0){
SwStatus = 1;
if(sw_data>4){
sw_data = 0;
}
sw_data++;
}
}
else{
SwStatus = 0;
}
}
else{
SwStatus = 0;
}
}
void pat1(void){
PORTB = 0x01;
__delay_ms(500);
PORTB = 0x02;
__delay_ms(500);
PORTB = 0x04;
__delay_ms(500);
PORTB = 0x08;
__delay_ms(500);
}
void pat2(void){
PORTB = 0x01;
__delay_ms(500);
PORTB = 0x03;
__delay_ms(500);
PORTB = 0x07;
__delay_ms(500);
PORTB = 0x0f;
__delay_ms(500);
}
void pat3(void){
PORTB = 0x0e;
__delay_ms(500);
PORTB = 0x0d;
__delay_ms(500);
PORTB = 0x0b;
__delay_ms(500);
PORTB = 0x07;
__delay_ms(500);
}
void pat4(void){
PORTB = 0x0e;
__delay_ms(500);
PORTB = 0x0c;
__delay_ms(500);
PORTB = 0x08;
__delay_ms(500);
PORTB = 0x00;
__delay_ms(500);
}

The problem with your design is that the CPU spends most of the time stuck in the __delay_ms() loops. It cannot respond to button pushes while it is busy counting through multiple calls to __delay_ms(500).
The solution is don't use a busy-loop to pass time. Instead, you have to allow the CPU to respond to other events while you monitor the passage of time. One way to do this is to record the timer tick count at the time of an event. And then repeatedly compare that previous tick value with the timer's current tick value within your while loop (while you continue to do other things such as checking whether the switch was pressed).
Since you have a __delay_ms() function, you probably have access to another function to get the timer's current tick value. In the example below I've assumed that this function is called __get_tick() but it may have a different name.
I've also taken the liberty of reducing all of your pattern functions into a multidimensional array. But don't get too distracted by that. The real solution I'm recommending is to use __get_tick() instead of __delay_ms().
#define NUM_PATTERNS 5
#define NUM_STEPS 4
uint8_t const patterns[NUM_PATTERNS][NUM_STEPS] = {
{0x00, 0x00, 0x00, 0x00}, // LEDs are off
{0x01, 0x02, 0x04, 0x08}, // pattern 1
{0x01, 0x03, 0x07, 0x0f}, // pattern 2
{0x0e, 0x0d, 0x0b, 0x07}, // pattern 3
{0x0e, 0x0c, 0x08, 0x00} // pattern 4
};
void main(void){
int current_pattern = 0;
int current_step = 0;
char prev_sw_data = 0;
uint32_t prev_tick = 0;
internal_osc();
io_int();
tmr0_int();
while(1){
bool was_switch_pressed = false;
bool has_500_ms_passed = false;
uint32_t current_tick = __get_tick();
// Check whether the switch has been pressed.
if (sw_data != prev_sw_data) {
was_switch_pressed = true;
// Remember the new sw_data setting.
prev_sw_data = sw_data;
// Change the pattern.
current_pattern = sw_data;
// Start at step 0 whenever the switch is pressed and
// the pattern is changed.
current_step = 0;
}
else {
// Check whether 500 ms has passed.
if ( (current_tick - prev_tick) > NUM_TICKS_IN_500_MS) )
{
has_500_ms_passed = true;
// Advance to the next step in the pattern
++current_step;
if (current_step >= NUM_STEPS) {
current_step = 0;
}
}
}
if (was_switched_pressed || has_500_ms_passed)
{
// Remember the new tick time.
prev_tick = current_tick;
PORTB = patterns[current_pattern][current_step];
}
}
}

The problem is that you are blocking the while(1) loop when you are in a pattern
One idea is to make the counter and give you a tact each 1ms and make the following change:
while(1){
check_if_50ms_passed{
switch(sw_data){
case 1 : pat1(); break;
case 2 : pat2(); break;
case 3 : pat3(); break;
case 4 : pat4(); break;
default : PORTB = 0x00;break;
}
}
}
You must keep a counter in each pattern:
void pat1(void){
couter_for_next_step++;
if(couter_for_next_step == 10)// 50ms * 10 steps = 500ms
{
couter_for_next_step = 0;
switch(port_change){
case 1 : PORTB = 0x01; break;
case 2 : PORTB = 0x02; break;
case 3 : PORTB = 0x04; break;
case 4 : PORTB = 0x08; break;
default: break;
}
}
and when you change the sw_data do not forget to:
couter_for_next_step = 10;
port_change = 1;
This will allow you to enter through the while(1) loop several times and also check the status of the pressed button
You can also add at a pressed button event to turn off the leds

you can use a ( high priority software ) interrupt for this
on a processor or OS that is able for multithreading you could use different threads, on a PIC you can use interrupts

Related

AVR Microcontrollers memory game

I am making a game where you need to repeat the sequence of LEDs that light up. This sequence is set by two LEDs. To repeat the sequence, I use the joystick.
I had an idea to make two bool arrays where True will indicate the left LED, and False will indicate the right LED. The first array must contain a random sequence(True/False) that needs to be repeated. When I push to one or the other side of the joystick, I want to write to the second array, respectively, True / False and all this time compare them.
This is what I have at the moment. (AT90USB647)
#define F_CPU 2000000UL
#include <avr/io.h>
#include <stdbool.h>
int main(void) {
MCUCR |= 0x80;
MCUCR |= 0x80;
DDRA = 0xFF;
PORTF = 0x20;
bool seq2[100];
while(1)
{
uint8_t x = PINF;
if(!(x & 0x20)) {
PORTA = 0x80;
}
else if(!(x & 0x08)) {
PORTA = 0x01;
}
else {
PORTA = 0x00;
}
}
}
The main question is how do I write True or False to an array when I push the joystick?
A basic approach could be:
#define F_CPU 2000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
volatile unsigned int counter;
static unsigned char pattern_position;
static unsigned char array_position;
static unsigned char pattern[] = {
0b01010101,
0b11010101,
0b10010101
};
ISR(TIMER0_COMPA_vect)
{
counter++;
}
int main(void)
{
MCUCR |= 0x80;
DDRA = 0xFF;
PORTF = 0x20;
// Timer initialization
// Mode: CTC
// Prescaler: 1024
TCCR0A = (1<<WGM01);
TCCR0B = (1<<CS02) | (1<<CS00);
// Calculate a correct time
//
// we want 1 ms -> f_TIMER0 = 1/T = 1/(1 * 10^-3)s = 1 kHz
//
// f_CPU f_CPU 20 MHz
// f_TIMER0 = ------------- -> OCR0A = ---------------- = ------------- = ~ 20 (It is not exactly 1ms but it is ok)
// k_H * OCR0A k_H * f_TIMER0 256 * 1 kHz
//
OCR0A = 20;
TIMSK0 = (1<<OCF0A); // Enable Timer0 Overflow Compare Match interrupt
// Show the sequence that the user should input
for (unsigned char i=0; i < sizeof(pattern)/sizeof(&pattern[0]); i++)
{
for (unsigned char j=0; j < 8; j +=2)
{
// There is possible a signal missing to show the user that the next pattern occurs!
PORTA = ((pattern[i]>>(j+1))<<PINA7) | ((pattern[i]>>j)<<PINA0);
// That the user can see the patterns a delay is necessary!
_delay_ms(1000);
}
}
// Signalize that the game starts
for (unsigned char i=0; i <8; i++)
{
PORTA ^= 0x81;
_delay_ms(1000);
}
TCNT0 = 0x00;
sei();
while(1)
{
// There is possible a signal missing to trigger next pattern input to the user!!!
if(!(PINF & (1<<PINF5)))
{
PORTA |= 0x80;
}
if(!(PINF & (1<<PINF3)))
{
PORTA |= 0x01;
}
// Time is 4 seconds to match the correct pattern
if(counter >= 4000)
{
if(!((pattern[pattern_position] & (1<<array_position)) == (0x01 & PORTA)))
{
// Wrong input end of game
}
array_position++;
if(!((pattern[pattern_position] & (1<<array_position)) == (0x01 & (PORTA>>8))))
{
// Wrong input end of game
}
array_position++;
if(array_position >= 8)
{
array_position = 0;
pattern_position++;
}
if(pattern_position >= (sizeof(pattern)/sizeof(&pattern[0])))
{
// End of game reached winning!
}
counter = 0x00;
PORTA = 0x00;
TCNT0 = 0x00;
}
}
}
I´m not sure if you are exactly trying this to do and i also can not test the code on your target platform but maybe this is a rudimental approach to solve your problem...

attiny13 pwm led complete on off

Sorry for my english. I have some issues on attiny13 with pwm. pwm works perfectly on adjustment. However while OCR0B value is going to zero or max, led not complete off or on. I tried use " PORTB &= ~ (1<<); " while OCROX was zero, but it doesnt work. afterwards I find that I must add " ISR(TIM0_COMPA_vect)" for interrupt. I have recently begun work on tiny ,so its too hard especially avr side for me and pls ignore my illiteracy. This is code, ı used.
#define F_CPU 1200000
#define LED PB1
#include <avr/io.h>
const int buttonPin = 4; // the pin that the pushbutton is attached to
int buttonPushCounter = 0; // counter for the number of button presses
int buttonState = 0; // current state of the button
int lastButtonState = 1;
int model; // previous state of the button
void setup() {
// initialize the button pin as a input:
pinMode(buttonPin, INPUT);
// initialize the LED as an output:
}
void adc_setup (void)
{
// Set the ADC input to PB2/ADC1
ADMUX |= (1 << MUX0);
ADMUX |= (1 << ADLAR);
// Set the prescaler to clock/128 & enable ADC
// At 9.6 MHz this is 75 kHz.
// See ATtiny13 datasheet, Table 14.4.
ADCSRA |= (1 << ADPS1) | (1 << ADPS0) | (1 << ADEN);
}
void pwm_setup (void)
{
// Set Timer 0 prescaler to clock/8.
// At 9.6 MHz this is 1.2 MHz.
// See ATtiny13 datasheet, Table 11.9.
TCCR0B |= (1 << CS01);
// Set to 'Fast PWM' mode
TCCR0A |= (1 << WGM01) | (1 << WGM00);
// Clear OC0B output on compare match, upwards counting.
TCCR0A |= (1 << COM0B1);
}
void pwm_write (int val)
{
OCR0B = val;
}
void button()
{
buttonState = digitalRead(buttonPin);
// compare the buttonState to its previous state
if (buttonState != lastButtonState) {
// if the state has changed, increment the counter
if (buttonState == HIGH) {
// if the current state is HIGH then the button went from off to on:
buttonPushCounter++;
model = buttonPushCounter % 5 ;
} else {
// if the current state is LOW then the button went from on to off:
}
// Delay a little bit to avoid bouncing
delay(250);
}
lastButtonState = buttonState;
}
int main (void)
{
int adc_in;
// LED is an output.
DDRB |= (1 << LED);
adc_setup();
pwm_setup();
while (1) {
// Get the ADC value
button();
//adc_in = adc_read();
// Now write it to the PWM counter
switch(model)
{
case 0:
pwm_write(0);
//PORTB &= ~ (1<<PB3);
break;
case 1:
pwm_write(50);
break;
case 2:
pwm_write(100);
break;
case 3:
pwm_write(150);
break;
case 4:
pwm_write(255);
//PORTB |= (1<<PB3);
break;
}
}
}
I find another code successfully turn on, off and adjust led via using interrupt with two button, but I dont understand how code write values on OCR0X. Could somebody can explain me the connection between OCR0X and duty(count, pwm value) at the second code . Because ı need write constant values in those OCR0X.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define PWM_PIN PB0
#define KEY_UP_PIN PB1
#define KEY_DOWN_PIN PB2
#define PWM_DUTY_MIN (0)
#define PWM_DUTY_MAX (100)
#define PWM_DUTY_STEP (1)
#define KEY_UP (1 << 1)
#define KEY_DOWN (1 << 2)
static volatile uint8_t duty = 0;
static uint8_t counter = 0;
static void process(void);
static uint8_t read_keys(void);
ISR(TIM0_COMPA_vect)
{
if (duty > PWM_DUTY_MIN && duty < PWM_DUTY_MAX) {
if (counter == 0) {
PORTB |= _BV(PWM_PIN);
} else if (counter == duty) {
PORTB &= ~_BV(PWM_PIN);
}
if (++counter == PWM_DUTY_MAX) {
counter = 0;
}
}
}
int
main(void)
{
/* setup */
DDRB |= _BV(PWM_PIN); // set PWM pin as OUTPUT
PORTB |= _BV(KEY_UP_PIN)|_BV(KEY_DOWN_PIN);
TCCR0A |= _BV(WGM01); // set timer counter mode to CTC
TCCR0B |= _BV(CS00); // set prescaler
OCR0A = 95; // set Timer's counter max value (96 - 1)
TIMSK0 |= _BV(OCIE0A); // enable Timer CTC interrupt
sei(); // enable global interrupts
_delay_ms(100); // time of debounce
/* loop */
while (1) {
process();
_delay_ms(8);
}
}
void
process(void)
{
uint8_t keys;
if (!(keys = read_keys())) {
return;
}
if ((keys & KEY_UP) && duty < PWM_DUTY_MAX) {
duty += PWM_DUTY_STEP;
}
if ((keys & KEY_DOWN) && duty > PWM_DUTY_MIN) {
duty -= PWM_DUTY_STEP;
}
if (duty == PWM_DUTY_MIN) {
PORTB &= ~_BV(PWM_PIN);
} else if (duty == PWM_DUTY_MAX) {
PORTB |= _BV(PWM_PIN);
}
}
static uint8_t
read_keys(void)
{
uint8_t result = 0;
if ((PINB & _BV(KEY_UP_PIN)) == 0) {
result |= KEY_UP;
}
if ((PINB & _BV(KEY_DOWN_PIN)) == 0) {
result |= KEY_DOWN;
}
return result;
}

Why is my Timer2 interrupt not working? Am I missing any register configs?

I am working on a project with the pic10f322 microcontroller. I've made a very basic communication protocol - there is a start pulse (10 ms) followed by a number of 5ms pulses (2 pulses - turns on a red light, 3 turns on yellow and 4 - green). So the following code is trying to read the communication protocol and turn on the respective light. I'm using TMR0 to measure the length of the pulse and count it. I have a bicolour LED (Red and Green) so I need to alternate the two to create the yellow. I was hoping to use TMR2 as an interrupt to allow me to pulse the yellow light separately from the rest of the code, so that it doesn't get in the way of my main function detecting start pulses.
I have no idea why it isn't working. I've checked the registers (although please do double check incase I'm blind to something). The code compiles.
I turned the light on at various stages of the code to check it, and the light turns on in every case statement, include the last one where I set the LedColour enum variable to the respective colour. When I try to turn the light on in the interrupt function, it never turns on.
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <pic.h>
#include <stdbool.h>
#include <pic10f322.h>
// crystal oscilator
define _XTAL_FREQ 1000000
// CONFIG
#pragma config FOSC = INTOSC // Oscillator Selection bits
#pragma config BOREN = OFF // Brown-out Reset disabled
#pragma config WDTE = OFF // WDT disabled
#pragma config PWRTE = OFF // PWRT disabled
#pragma config MCLRE = OFF // MCLR pin function
#pragma config CP = OFF // Code Protection disabled
#pragma config LVP = ON // Low-voltage programming enabled
#pragma config LPBOR = OFF // Brown-out Reset disabled
#pragma config BORV = LO // Brown-out Reset Voltage, low trip point
#pragma config WRT = OFF // Flash Memory Write protection off
void timer2_isr(void);
#pragma code high_vector=0x08;
void interrupt (void)
{
asm("GOTO timer2_isr");
}
#pragma code
#pragma interrupt timer2_isr
#define RED_LED 0x01
#define GREEN_LED 0x02
#define SetBit(bit) (PORTA |= bit )
#define ClearBit(bit) (PORTA &= ~bit)
#define TestBit(bit) ( PORTA&bit)
int clkval = 0;
int pulsecnt = 0;
enum {
Red,
Green,
Yellow,
Off,
} LedColor = Off;
void timer2_isr (void)
{
PORTA = 0b1101; //This turns a green light on if it enters this function
if (PIR1 == 0x02)
{
PIR1 = 0x00;
}
}
void main(int argc, char** argv)
{
OSCCON = 0x30; //1MHz Clk
TRISA = 0x0C;
ANSELA = 0x00;
PORTA = 0x0C;
OPTION_REG = 0x06;
T2CON = 0x04; //Timer2 Registers Prescaler= 1 - TMR2 PostScaler = 1 - PR2 = 254 - Freq = 980.39 Hz - Period = 0.001020 seconds
PIE1 = 0x02;
PIR1 = 0x00;
TMR0 = 0;
TMR2 = 0;
PR2 = 254;
INTCON = 0xC0;
__delay_ms(2000);
enum {
WaitForStart,
CountPulses,
SelectColor,
} State = WaitForStart;
while (1)
{
switch (State)
{
case WaitForStart: //wait for start pulse
if ( (PORTA & 0x04) != 0x04 )
{
TMR0 = 0;
while ((PORTA & 0x04) != 0x04)
{
clkval = TMR0;
}
if (18 < clkval < 22)
{
State = CountPulses;
pulsecnt = 0;
}
}
break;
case CountPulses: // found start pulse, now count pulses or reset
if ( (PORTA & 0x04) != 0x04 )
{
TMR0 = 0;
while ((PORTA & 0x04) != 0x04)
{
clkval = TMR0;
}
if (8 < clkval < 12)
{
pulsecnt++;
}
}
if ((PORTA & 0x04) == 0x04)
{
clkval = 0;
TMR0 = 0;
while ((PORTA & 0x04) == 0x04 && clkval < 45)
{
clkval = TMR0;
if ((44 < clkval) || (pulsecnt > 4)) //no pulses noticed in over 22ms comparison or if you have surpassed the max number of pulses you are supposed to reach
{
if (pulsecnt > 0)
{
State = SelectColor;
} //if there has been a long delay, and pulses have been detect (so pulsecnt is greater than 0) then move to next case
else
{
State = WaitForStart;
} // if long delay and no pulses have been detected, restart and check for start pulse again
}
}
}
break;
case SelectColor: // if pulses have been detected, this state will be visited after long delay ( >22ms)
if (pulsecnt == 2)
{
LedColor = Red;
//PORTA = 0b1110;
State = WaitForStart;
}
else if (pulsecnt == 3)
{
LedColor = Yellow;
State = WaitForStart;
}
else if (pulsecnt == 4)
{
LedColor = Green;
//PORTA = 0b1101;
State = WaitForStart;
}
else
{
LedColor = Off;
State = WaitForStart;
}
break;
default:
State = WaitForStart;
break;
}
}
}
I used "PORTA = 0b1101", which turns the green light on. as a test line to step through the code and make sure it's reach certain points. Right now it is at the beginning of the interrupt, so it should turn on and stay on righht after the first interrupt which would happen within approximately 2.5ms I think? Or relatively quickly anyway, but it never gets inside the interrupt function or the function before which uses assembly to tell it to goto this function.
In PIC16, you need to start the timer separately from the rest of the config, like that:
T2CONbits.TMR2ON = 1;
Also, check that you have enabled the interrupts:
INTCONbits.PEIE = 1;
INTCONbits.GIE = 1;
I suggest using the above notation for initialization; what you have is hard to verify.
The PIC 10 has got only one interrupt vector and that is on address 0x04 (not 0x08 as you expected).
Try somethig like this:
void interrupt myISR(void)
{
........
}
This init function gets a TMR2 interrupting at high priority
on a PIC18F25K80
void pwm_mosfet_stepper_init() {
TMR2 = 0;
RCON |= (1<<7); // IPEN = 1;
PR2 = 100; // 100; // 100==#16uS 1.6ms
//
INTCON |= ( (1<<6) | (1<<7) ); // GIE/GIEH PEIE/GIEL i.e. both low and high enabled
// .......................... post4 ON pre4
//T2CON = 0x1D; // 2us tick ON 11 1 01
// .......................... post4 ON pre16
T2CON = 0x1F; // 16us tick ON 11 1 1X
IPR1 |= (1<<1); // TMR2IP = 1; HIGH PRIORITY
PIE1 |= (1<<1); // TMR2IE = 1; // interrupts are GO!
}

C - button pressed once registered twice - MSP430

I wanted to create a game where a player has to repeat a random pattern of flashing lights with the keys on the MSP430. The random pattern is created with an ADC - 0 represents the red light on P1.0 blinking and 1 the green light on P4.7.
After playing it myself I noticed that sometimes when I press a button once it is registered as pressed twice.
For example: The pattern is red/red/red/green (0/0/0/1) then pressing the left button twice and the right button once is enough because the first push of the left button is registered as two pushes.
I reduced the code of the game to a smaller program in which it's only necessary to repeate the pattern of the example above:
#include <msp430.h>
int pattern[4];
unsigned int index = 0;
unsigned int button;
unsigned int buttonPressed = 0;
void Initialize_LED(void)
{
P4DIR = P4DIR | 0x80;
P4OUT &= ~0x80;
P1DIR = P1DIR | 0x01;
P1OUT &=~0x01;
pattern[0] = 0;
pattern[1] = 0;
pattern[2] = 0;
pattern[3] = 1;
}
void Initialize_Buttons(void){
P1REN |= 0x02;
P1OUT |= 0x02;
P2REN |= 0x02;
P2OUT |= 0x02;
P1IFG &= ~0x02;
P2IFG &= ~0x02;
P1IE |= 0x02;
P2IE |= 0x02;
//Timer:----------------------------
TA1CTL = TASSEL_1+ID_0+MC_2+TACLR; //
TA1R = 40000; //
// ----------------
_BIS_SR(GIE);
}
void main(void)
{
WDTCTL = WDTPW + WDTHOLD;
Initialize_LED();
Initialize_Buttons();
int done = 0;
while(done == 0){
if(buttonPressed == 1){
if(pattern[index] != button){
P1OUT ^= 0x01;
done++; //wrong button --> green light on
} else {
index++;
buttonPressed = 0;
if (index == 4){
done++;
}
}
}
}
P1OUT ^= 0x01; // correct pattern --> both lights on
P4OUT ^= 0x80;
}
#pragma vector=PORT1_VECTOR // ----------- Interrupt Service Routine -----------
__interrupt void Port1_Interrupt (void) {
buttonPressed = 1;
if (P1IFG&0x02){
button = 1;
P1IE &= ~0x02;
TA1CTL |= TAIE;
TA1R = 50000;
}
}
#pragma vector=PORT2_VECTOR // ----------- Interrupt Service Routine -----------
__interrupt void Port2_Interrupt (void) {
buttonPressed = 1;
if (P2IFG&0x02){
button = 0;
P2IE &= ~0x02;
TA1CTL |= TAIE;
TA1R = 50000;
}
}
#pragma vector=TIMER1_A1_VECTOR // Timer1_A3 Interrupt Vector(TAIV) handler
__interrupt void TIMER1_A1_ISR(void)
{
switch (__even_in_range(TA1IV, 14))
{
case 0: break;
case 2: break;
case 4: break;
case 6: break;
case 8: break;
case 10: break;
case 12: break;
case 14:
P1IFG &= ~0x02;
P1IE |= 0x02;
P2IFG &= ~0x02;
P2IE |= 0x02;
TA1CTL &= ~TAIE;
break;
default: break;
}
}
I went through the code with the debugger but can't find the reason why this keeps happening. Is someone able to help me? Thanks for your time!
Every mechanical contact generate pulses - bounces during switch ON and also OFF. You need create an debouncing filter for this.
My proposals is for you to completely avoid interrupts for reading status of buttons.
Best way to debounce buttons by SW is to sample it with sampling time longer than button generate bounce pulses (it is generally about 1-10ms).
You can do it by reading actual status of buttons every 10ms and compare it with previous status. Then you will have completely debounced button(s).
I use this method in many projects, where I don't need HW filter and same principle is used for example in any PC keyboard, where HW filter is not possible to add, because all the buttons are multiplexed, but this is better to discus on https://electronics.stackexchange.com

PIC16F883 Led Blink

I need to program a PIC16F883 to blink / light up LED's at the same time. The oscillator is running at 3,2768, and I'm using TIMER0 to help me with the timing.
Right now, I have a prescaler set to 1:256, so I get an interrupt every 50ms, and I have a variable that is calculated from that, to display how many seconds has gone.
If the input is changed, the seconds variable is of course reset again.
Here is the assignment from my teacher:
If Input is 0 (Closed):
The Red And The Green LED should be turned on at the same time for 15 seconds. After this the green LED should be turned
off completely, and the red LED should blink every fifth second for 10 minutes
If input is 1 (Opened):
The red LED should be turned off completely, and the green LED should be turned on for 10 minutes, and after that
it should be turned off too.
My timer is working fine. I have tested that. The program runs fine too and keeps the 2 LED's turned off for 15 seconds, then turns them off, but my red LED isn't blinking. I have been sitting at my desk all day desperately trying to find the error in my code.
Picture of the print:
Here is my C Code. I am using MPLab and the HI-TECH C compiler :)
#include <pic.h>
//Variabler
int B = 0; //Definerer variablen B, used as a flag
int A = 0; //Definerer veriablen A, used as a flag
int E = 0;
int savedstatus = 1; //Definere variablen savedstatus used to check last status for input
int millicounter = 0; //Variabel to calculate seconds
int sec = 0; //Variabel holding seconds gone
int count = 0; //For counting seconds passed, used in input0 subroutine
int onesec = 0; //Used to counting seconds for blinking LED in input0 subroutine
int scount = 0;
//Variabler slut
void interrupt jesper(void)
{
T0IF = 0x00;
TMR0 = 96;
millicounter++;
if(millicounter == 20)
{
sec++;
millicounter = 0;
}
}
//Subrutines
void input0()
{
if(sec<=15 && E==0)
{
PORTA = 0x21;
}
else if(A==0)
{
scount = 0;
sec = 0;
count = sec;
A = 1;
E = 1;
}
else if(sec<=600 && sec>count)
{
count++;
if((scount+5)>=count)
{
if(B==0)
{
onesec = sec;
B = 1;
PORTA = 0x01;
}
else if(sec>onesec)
{
PORTA = 0x00;
B = 0;
scount = count;
scount;
}
else
{
PORTA = 0x01;
}
}
else
{
PORTA = 0x00;
}
}
else PORTA = 0x00;
}
void input1()
{
if(sec<=600)
{
PORTA = 0x20;
}
else
{
PORTA = 0x00;
}
}
//Subrutines over
int main(void)
{
TRISA = 0x00; //Sets all A-PORTS to output
TRISB = 0x01; //Sets all PORTB to output with the exception of BIT0
TRISC = 0x00; //Sets All PORTC to output
ANSEL = 0x00; //Disable Analog ports
ANSELH = 0x00; //Disable Analog ports
//Timer Config
PSA = 0x00;
PS0 = 0x01;
PS1 = 0x01;
PS2 = 0x01;
TMR0 = 0x60;
GIE = 0x01;
T0IE = 0x01;
T0IF = 0x00;
T0CS = 0x00;
//Timer Config Over
while(0x01)
{
if(savedstatus != RB0)
{
savedstatus = RB0;
sec = 0;
E = 0;
A = 0;
}
if(savedstatus == 1)
{
input1();
}
else
{
input0();
}
}
}
I really hope that you can help me here :)
Here is my flowchart for the subroutine input0 where my problem is. Btw some of my variables have different names in the code itself, but it shouldn't be hard to see.
Your main() calls input0() as often as possible. When input0() is in the flashing state it uses the conditional sec > count. I suspect that your intention is that input0() should only change the LED state at intervals of a second. But then on the else side of that conditional you turn both LEDs off. This else side is executing many times because main() is calling input0() so often. Try deleting the else condition where you turn the LEDs off.
void input0()
{
<snip>
else if(sec<=600 && sec>count)
{
<snip>
}
else PORTA = 0x00; // <-- delete this line so you're not always turning the LED off
}

Resources