I am working on a personal project, hacking a multimeter and adding backlight to it. I am using an Attiny13.
I have the following code:
/* IR_Switch.c
*
* Created: 30/11/2014 23:52:15
* Author: keenox
*/
#define F_CPU 128000UL // 128kHz osc, no prescaling
#define SEC(VAL) ((unsigned int)(VAL) * F_CPU / 256)
#define INV_SEC(VAL) (F_CPU / 256 / (unsigned int)(VAL))
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/sleep.h>
#define FORCE_INLINE //__attribute__((always_inline))
#define PWM_ON() do { TCCR0A |= _BV(COM0A1); } while (0)
#define PWM_OFF() do { TCCR0A &= ~_BV(COM0A1); } while (0)
#define COUNTER_ON() do { counter = 0; TIMSK0 = _BV(TOIE0); } while (0)
#define COUNTER_OFF() do { TIMSK0 = 0; } while (0)
#define LED_ON() ( (TCCR0A & _BV(COM0A1)) || (PORTB & _BV(PINB0)) )
#define BUTTON_DOWN() ((~PINB) & _BV(PINB3))
#define BUTTON_UP() (PINB & _BV(PINB3))
#define TIMEOUT 15
char step = 50;
unsigned long counter = 0;
void ledFull(unsigned char _val)
{
PWM_OFF();
if (_val)
PORTB |= _BV(PINB0);
else
PORTB &= ~_BV(PINB0);
}
void setLed()
{
if (OCR0A > 249)
ledFull(1);
else if (OCR0A < 6)
ledFull(0);
else
PWM_ON();
}
ISR(TIM0_OVF_vect)
{
counter++;
if (BUTTON_UP())
{
if (counter >= INV_SEC(4))
{
PORTB |= _BV(PINB4);
if (!LED_ON())
{
COUNTER_OFF();
}
else if (counter >= SEC(TIMEOUT))
{
ledFull(0);
COUNTER_OFF();
}
}
}
else if (counter > SEC(3))
{
// Change intensity every one sec while button down
counter -= SEC(1);
if (OCR0A > 249 || OCR0A < 6)
step = -step;
OCR0A += step;
setLed();
}
}
ISR(PCINT0_vect)
{
cli();
PCMSK = 0x0;
if (BUTTON_DOWN())
{
MCUCR |= _BV(ISC00); // Switch to rising edge
COUNTER_ON();
}
else
{
MCUCR &= ~_BV(ISC00); // Switch to falling edge
if (counter <= INV_SEC(2)) // Normal push
{
PORTB &= ~_BV(PINB4);
}
else if (counter <= SEC(2))
{
if (LED_ON())
{
ledFull(0);
COUNTER_OFF();
}
else
{
setLed();
}
}
}
PCMSK = _BV(PCINT3);
sei();
}
int main(void)
{
DDRB = _BV(PINB4) | _BV(PINB0); // All inputs, but PB4 output
PORTB = 0xFF & ~_BV(PINB0); // All 1, except PINB0
MCUCR |= _BV(ISC01); // Falling edge interrupt
GIMSK = _BV(PCIE); // Activate only pin change interrupt
PCMSK = _BV(PCINT3); // PB3 interrupt mask
TCCR0A = _BV(WGM01) | _BV(WGM00); // Set OC0A at TOP, Fast PWM
TCCR0B = _BV(CS00); // Timer on, No prescaling
OCR0A = 255; // Max bright
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
COUNTER_OFF();
while (1)
{
sleep_enable();
#if defined(sleep_bod_disable)
sleep_bod_disable();
#endif
sei();
sleep_cpu();
sleep_disable();
}
}
The problem is it wakes up only on first interrupt (button push), executes it and then nothing.
If I don't use sleep (leave only while(1);) the program runs as expected.
Do you know what could be the problem?
LE: Added full code.
If I have:
sei();
while (1) {}
Then everything works OK. I just want to use sleep to reduce consumption.
Your sleep mode is "Power-down Mode"
as described in 7.1.3 of the reference manual
"Only an External Reset, a Watchdog Reset, a Brown-out
Reset, an external level interrupt on INT0, or a pin change interrupt can wake up the MCU. This sleep mode halts all generated clocks"
So the push button interrupt is handled, however the timer interrupt you enable at push button never fires because returning to sleep mode disables the timer.
You want the "Idle" sleep mode.
Related
I'm trying to create a 10 second delay using TIMER1(16 bit) in atmega328p, I don't know if the delay has been created or not because it takes longer duration than 10 seconds and expected output( which is to create pwm waves) is not obtained. Here I have created a 1second delay and looped it 10 times, TIMER0 is used for creating pwm waves.
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "interrupt.h"
#define SET_BIT(PORT,BIT) PORT |= (1<<BIT)
#define CLR_BIT(PORT,BIT) PORT &= ~(1<<BIT)
struct {
volatile unsigned int BIT: 1;
}
FLAG_TIMER;
void timer_configuration() //16 bit timer
{
TCCR1A = 0x00; // Normal mode of operation
TCNT1 = 0xC2F8;
TCCR1B |= ((1 << CS10) | (1 << CS12));
TCCR1B &= ~(1 << CS11); //101
sei(); // Global interrupt
}
void timer_on()
{
TIMSK1 |= (1 << TOIE1);
}
void pwm_configuration() //TIMER0 - 8 bit
{
TCCR0A |= ((1<<WGM00) | (1<<WGM01)); //setting it to fast PWM mode
TCCR0A |= (1<<COM0A1);
TCCR0A &= ~(1<<COM0A0);
TCNT0 = 0x00;
TCCR0B |= ((1<<CS00) | (1<<CS02)); //Prescaler setting 1024
TCCR0B &= ~(1<<CS01);
sei();
}
ISR(TIMER1_OVF_vect)
{
static unsigned int counter;
counter++;
if(counter >= 10)
{
FLAG_TIMER.BIT=1;
counter = 0;
TCNT1 = 0xC2F8;
TIMSK &= ~(1<< TOIE1);
}
else
{
FLAG_TIMER.BIT=0;
}
}
int main(void)
{
SET_BIT(DDRD,PD6); //CRO
timer_configuration();
pwm_configuration();
while(1)
{
timer_on();
if(FLAG_TIMER.BIT == 1)
{
OCR0A = 128; //50% dutycycle
}
}
You set the counter to 49912 on initialisation and increment your count when it overflows, but it will then start from 0, so if 15624 counts = 1 second, then your counter will increment to 10 after 15624 + 9 x 216 counts or about 38.75 seconds.
Move the TCNT1 = 0xC2F8; line in the ISR:
ISR(TIMER1_OVF_vect)
{
static unsigned int counter;
TCNT1 = 0xC2F8;
counter++;
if(counter >= 10)
{
FLAG_TIMER.BIT=1;
counter = 0;
TIMSK &= ~(1<< TOIE1);
}
else
{
FLAG_TIMER.BIT=0;
}
}
I am not familiar with ATmega, but I cannot believe that is an appropriate way to use the timer. Normally you'd up-count to a compare value with auto reset to zero, or down-count from an auto reload value to zero and let the hardware reload the counter.
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...
I have tried to implement TX only uart for ATTiny85 and receive the bits using arduino micro. (similiar question did not help since it is quite different to my situation)
My intend is to be able to print via attiny85 -> arduino -> console so I can debug the attiny85, since I don't have oscilloscope available.
attiny85 fuses are: "efuse:w:0xff:m -U hfuse:w:0xdf:m -U lfuse:w:0xf1:m" aka. 16MHz F_CPU
arduino also seems to have 16MHz F_CPU
Similiar to the mentioned question attiny85 sends bits via timer0 ISR one bit at time:
#ifndef F_CPU
#define F_CPU 16000000UL // 16 MHz
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define TX_PIN PB0
volatile uint16_t tx_shift_reg = 0;
ISR(TIMER0_COMPA_vect) {
uint16_t local_tx_shift_reg = tx_shift_reg;
if( local_tx_shift_reg & 0x01 ) {
PORTB |= _BV(TX_PIN);
} else {
PORTB &= ~_BV(TX_PIN);
}
local_tx_shift_reg >>= 1;
if(!local_tx_shift_reg) {
// Stop timer0.
GTCCR |= (1<<TSM) | (1<<PSR0);
}
tx_shift_reg = local_tx_shift_reg;
}
void UART_tx(char byte) {
uint16_t local_tx_shift_reg = tx_shift_reg;
local_tx_shift_reg = (0b1<<9) | ((uint16_t)byte<<1);
tx_shift_reg = local_tx_shift_reg;
TCNT0 = 0;
TCCR0B |= (1<<CS02)|(1<<CS00); // 1024 prescaler
GTCCR &= ~(1<<TSM);
}
void UART_tx_char(char c) {
UART_tx( c );
// wait until transmission is finished
while(tx_shift_reg);
}
void UART_init() {
cli()
// set TX pins as output
DDRB |= (1<<TX_PIN);
PORTB |= (1<<TX_PIN);
// set timer0 to CTC mode, keep it halted.
TCCR0A |= (1<<WGM01);
TCCR0B = 0;
// enable interrupt
TIMSK |= (1<<OCIE0A);
OCR0A = 128;
OCR0B = 128;
TCNT0 = 0;
GTCCR |= (1<<TSM);
sei();
}
void main(void)
{
UART_init();
while(1) {
for(char c = 1; c < 128; ++c) {
UART_tx_char(c);
_delay_ms(100);
}
}
}
Then arduino receives the bits:
/*
* ATtiny85 bit-bang uart monitor for ATmega32u4
*/
#define LED_PIN 13
#define RX_PIN 7
// rx_state == 0 // timer1 not running
// rx_state == 1 // receive in progress
// rx_state == 2 // data ready in rx_data_reg
volatile int rx_state = 0;
volatile int rx_bit_nro = 0;
volatile uint16_t rx_shift_reg = 0;
volatile uint16_t rx_data_reg = 0;
void rx_start_interupt() {
if(rx_state == 0) {
digitalWrite(LED_PIN, HIGH);
while(digitalRead(RX_PIN));
// Start timer1
rx_state++;
TCNT1 = 0;
TCCR1B = (1 << WGM12) | (1 <<CS12) | (1 << CS10);
}
}
ISR(TIMER1_COMPA_vect) {
uint16_t bit = digitalRead(RX_PIN) > 0;
rx_shift_reg >>= 1;
rx_shift_reg |= (bit << 7);
++rx_bit_nro;
if(rx_bit_nro == 9) {
// Stop timer.
TCCR1B = 0;
TCNT1 = 0;
rx_data_reg = rx_shift_reg;
rx_shift_reg = 0;
rx_bit_nro = 0;
rx_state++;
digitalWrite(LED_PIN, LOW);
}
}
void setup() {
noInterrupts();
// Program timer1 for UART bit bang receive.
TCCR1A = 0; // set entire TCCR1A register to 0 (stops it)
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
OCR1A = 128;
TIMSK1 |= (1 << OCIE1A);
interrupts();
pinMode(LED_PIN, OUTPUT);
pinMode(RX_PIN, INPUT);
// Attach RX start interupt.
pinMode(digitalPinToInterrupt(RX_PIN), INPUT);
attachInterrupt(digitalPinToInterrupt(RX_PIN), rx_start_interupt, FALLING);
Serial.begin(9600);
while(!Serial);
Serial.print("F_CPU:");
Serial.println(F_CPU,DEC);
Serial.println("Waiting for data from attiny85...");
}
void loop() {
if(rx_state == 2) {
uint16_t local_rx_data = rx_data_reg;
rx_state = 0;
Serial.println(local_rx_data,HEX);
}
}
I have tried pretty much everything to make it work, but received bytes come back garbace.
What am I missing?
Note: I'm using timer0 on attiny85 and timer1 on arduino.
Solved: switching ISR to TIMER1_COMPAB_vect and OCR1B = 64 actually works! Yay!
I recently ran into this issue of serial comms coming out as garbage on the other end. In my case, the ATtiny85 was sending bits to my laptop using an USB to TTL UART converter which had worked beautifully in other situations, but, I was just getting garbage in the Arduino IDE serial monitor.
I found a forum post which mentioned the possibility of calibrating OSCCAL.
I get a little bit fancier in my related blog post, but I tested the theory that I should calibrate OSCCAL using this code:
#include <SoftwareSerial.h>
SoftwareSerial comm(-1, 0);
static const int anchor = 128;
void
print_osccal(int v) {
comm.println(F("********************************"));
comm.print(F("OSCCAL = "));
comm.println(v);
comm.println(F("********************************"));
}
void
setup() {
delay(5000);
comm.begin(300);
OSCCAL = anchor;
print_osccal(anchor);
delay(5000);
}
void
loop() {
int x;
for (int i = 1; i < 128; ++i) {
x = anchor + i;
OSCCAL = x;
print_osccal(x);
delay(1000);
x = anchor - i;
OSCCAL = x;
print_osccal(x);
delay(1000);
}
}
It was a revelation seeing garbage all of a sudden transform to nicely formatted messages in the serial monitor (and, of course, back to garbage as the search is an infinite loop).
Now, the ATtiny85's internal oscillator can only support 1 MHz and 8 MHz. As I understand it, OSCCAL exists because this internal oscillator is 1) not very accurate and 2) is very sensitive the temperature.
If the ATtiny85 is set to run at 16MHz, it needs a reliable, external oscillator, and no amount of fiddling with OSCCAL might help. But, it did in my case allow me to discover the value(s) which made SoftwareSerial tick at 8 MHz and a range of baud rates from 300 to 38400.
This allowed me to get the right value for the bit banging UART to work with the 1MHz clock which is not supported by SoftwareSerial.
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;
}
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!
}