Hi everyone, I'm looking for some help for a project I'm working on.
I'm working with an Arduino Nano with an ATmega328P. I have basic understanding of operators, pointers, GPIO's, ADC converts etc. I've been learning about the Arduino IDE for 3 months now.
I am trying to use Timer1 to generate an interrupt every 100 msec. Then inside this timer, measure the uC temp using starting an ADC conversion. Then using an ADC ISR to update global memory to the last 10 measurements at 10Hz.
What I can't figure out is how to call/flag the ADC ISR after the timer1 ADC takes place to then gather 10 measurements. Below is my ADC ISR temperature program:
#include <stdint.h>
#include <Arduino.h>
#include "avr/interrupt.h"
// global variables
volatile uint8_t * ioPORTB;
volatile uint8_t * ioDDRB;
volatile uint8_t * ioPINB;
volatile uint8_t * pADMUX;
volatile uint8_t * pADCSRA;
volatile uint8_t * pADCL;
volatile uint8_t * pADCH;
volatile uint8_t * pSREG;
uint8_t msg[80];
uint16_t g_adcResult;
ISR(ADC_vect, ISR_BLOCK)
{
//ADC conversion complete
g_adcResult = *pADCL; // lower 8 bits of result
g_adcResult = g_adcResult | (((uint16_t)*pADCH) << 8); // 0x ADCH byte | ADCL byte
g_adcResult = g_adcResult & 0x03FF; // clear bits 15 - 10 (ADC result is only 10 bits)
}
int main(void)
{
init();
float voltage;
ioPORTB = (uint8_t *)0x25;
ioDDRB = (uint8_t *)0x24;
ioPINB = (uint8_t *)0x23; // PINB register [pb7 pb6 pb5 .. etc]
// setup points to MMR for ADC
pADMUX = (uint8_t *)0x7C;
pADCSRA = (uint8_t *)0x7A;
pADCL = (uint8_t *)0x78;
pADCH = (uint8_t *)0x79;
pSREG = (uint8_t *)0x5F;
uint16_t result;
// make PB1 an output
*ioDDRB = 0x02; // DDRB[7:0] = 0000 0010
//configure ADC periperial
*pADMUX = 0xC8; // 1100 1000 REFS = 1.1v, MUX = 1000
*pADCSRA = 0x8F; // 1000 1111 ADEN = 1, ADIE = 1 (interupt enabled), ADPS = 111 (divide by 128 i.e. 16MHz / 128 = 125 kHz)
//Once a converison completes, ADIF/ADC Flag is set
// init serial port
Serial.begin(9600);
// sent out start of program message
sprintf((char *)msg, "start of program\n");
Serial.write((char *)msg);
while(1)
{
// set PB1 high
*ioPORTB = 0x02; // 0000 0010
// Read ADC channel ADC0
*pADCSRA = (*pADCSRA) | 0x40; // start a conversion
//write result to serial port
*pSREG = (*pSREG) & (~0x80); // clear bit 7 disable interrupts globally
voltage = (float)g_adcResult * (1100.0/1024.0);
sprintf((char *)msg, "result = %d\n", g_adcResult);
*pSREG = (*pSREG) | (0x80); // set bit7: enable interrupts globally
Serial.write((char *)msg);
sprintf((char *)msg, "voltagemV = %d\n", (uint16_t)voltage);
Serial.write((char *)msg);
// set PB1 low
*ioPORTB = 0x00; // 0000 0000
}
return 0;
}
Below is my proof of concept of a timer1 interrupt that toggles the onboard LED every 100msec.
//timer1 will interrupt at 10Hz
#include <stdint.h>
#include <Arduino.h>
#include "avr/interrupt.h"
//storage variables
boolean toggle1 = 0;
volatile uint8_t * ioPORTB;
volatile uint8_t * ioDDRB;
volatile uint8_t * ioPINB;
uint8_t x;
void setup(){
//set pins as outputs
pinMode(13, OUTPUT);
x = 0;
cli();//stop interrupts
//set timer1 interrupt at 10Hz
TCCR1A = 0;// set entire TCCR1A register to 0
TCCR1B = 0;// same for TCCR1B
TCNT1 = 0;//initialize counter value to 0
// set compare match register for 10hz increments
OCR1A = 1562;// = (16*10^6) / (1*1024) - 1 (must be <65536)
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS12 and CS10 bits for 1024 prescaler
TCCR1B |= (1 << CS12) | (1 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei();//allow interrupts
}//end setup
ISR(TIMER1_COMPA_vect){//timer1 interrupt 10Hz toggles pin 13 (LED)
//generates pulse wave of frequency 10Hz/2 = 5kHz
if (toggle1){
digitalWrite(13,HIGH);
toggle1 = 0;
}
else{
digitalWrite(13,LOW);
toggle1 = 1;
}
}
I just can't figure out how to combine the two programs above. Create 100msec interrupt using Timer1, begin ADC, then use ISR(ADC_Vect) or ISR(TIMER1_COMPB_vect). I would appreciate any help as I've spent the last 10 hours trying to logically figure this out.