Last active
February 8, 2020 02:08
-
-
Save natecostello/eedfdf9f183809a81ce9e38401749f52 to your computer and use it in GitHub Desktop.
Example of Addressing Atmega Registers from Arduino Code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Potentiometer.h> | |
#include <SegmentDisplay.h> | |
/* Runs the strobe light */ | |
// constants related to firmware configuration | |
const word minFrequency = 1; //hz | |
const word maxFrequency = 100; //hz | |
const int currentOnPeriod = 200; //microseconds | |
//variables related to hardware inputs | |
float currentFrequency; //hz | |
float inputFrequency; //hz | |
int tensInput; | |
int onesInput; | |
int tenthsInput; | |
//variables related to interrupts | |
int count; | |
//prescale value (this must be consistent with the prescale value set | |
//in timer1 configuration - use a forced case later during code clean | |
//up) | |
int prescale; | |
//controls | |
Potentiometer tensPot = Potentiometer(1); | |
Potentiometer onesPot = Potentiometer(2); | |
Potentiometer tenthsPot = Potentiometer(3); | |
//display | |
SegmentDisplay segDisplay; | |
void setup() { | |
//display | |
segDisplay.begin(1); | |
//controls | |
tensPot.setSectors(10); | |
onesPot.setSectors(10); | |
tenthsPot.setSectors(10); | |
//set current frequency | |
currentFrequency = 1; | |
//initialize pin for testing (LED on 12) | |
pinMode(12, OUTPUT); | |
pinMode(13, OUTPUT); | |
//interrupt setup | |
//enabling compare timer1 A interrupt | |
bitSet (TIMSK1, OCIE1A); | |
//enabling CTC mode | |
bitClear (TCCR1A, WGM10); | |
bitClear (TCCR1B, WGM11); | |
bitSet (TCCR1B, WGM12); | |
//prescale by 256 | |
bitClear (TCCR1B, CS10); | |
bitClear (TCCR1B, CS11); | |
bitSet (TCCR1B, CS12); | |
prescale = 256; | |
//set count corresponding to frequency | |
count = word(16000000/prescale/currentFrequency -1); | |
//need to find handle for system clock frequency | |
//also need to find a good rounding function | |
//set compare register | |
OCR1A = count; | |
//clear timer | |
TCNT1 = 0; | |
} | |
void loop() { | |
readControls(); | |
updateDisplay(); | |
} | |
//interrupt handler | |
ISR(TIMER1_COMPA_vect){ | |
turnOn(); | |
delayMicroseconds(currentOnPeriod); | |
turnOff(); | |
} | |
void readControls(){ | |
tensInput = tensPot.getSector(); | |
onesInput = onesPot.getSector(); | |
tenthsInput = tenthsPot.getSector(); | |
inputFrequency = tensInput*10+onesInput+tenthsInput/10.0; | |
if (inputFrequency > maxFrequency) { | |
inputFrequency = maxFrequency; | |
} | |
if (inputFrequency < minFrequency) { | |
inputFrequency = minFrequency; | |
} | |
if (inputFrequency != currentFrequency) { | |
currentFrequency = inputFrequency; | |
updateFrequency(); | |
} | |
} | |
void updateFrequency() { | |
count = word(16000000/prescale/currentFrequency - 1); | |
OCR1A = count; | |
TCNT1 = 0; | |
} | |
void turnOn(){ | |
digitalWrite(12, HIGH); | |
digitalWrite(13, HIGH); | |
} | |
void turnOff(){ | |
digitalWrite(12, LOW); | |
digitalWrite(13, LOW); | |
} | |
void updateDisplay(){ | |
segDisplay.display(currentFrequency); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Button.h> | |
#include <StrobeDisplay.h> | |
#include <Encoder.h> | |
/* | |
Runs the strobe light | |
Uses Timer1 - Fast PWM (mode 15) method for strobing. | |
Requires AuduinoMega or AtMega2560 | |
Requires the Following Pins: | |
Digital Pin 12 - Strobe Signal | |
Digital Pin 9 - Mode Button | |
Digital Pin 16 - Serial 2 TX | |
Digital Pin 8 - Decade Button | |
Digital Pin 5,6,7 - Fine Encoder | |
Digital Pin 2,3,4 - Coarse Encoder | |
Has not implemented the MODE function | |
*/ | |
//Debuging | |
const int DEBUG = 1; | |
//frequency bands | |
const int minFreqBand = 0; | |
const int maxFreqBand = 3; | |
int freqBand; //0, 1, 2, or 3 | |
const int freqBandLow[] = {1, 5, 50, 250}; | |
const int freqBandHigh[] = {5, 50, 250, 10000}; | |
const int freqBandPrescale[] = {256, 64, 8, 1}; | |
const float freqBandTick[] = {16, 4, 0.5, 0.0625}; //usec | |
//max and min frequency | |
const int freqMin = 1; | |
const int freqMax = 1000; | |
//control bands | |
const int minControlDec = 0; | |
const int maxControlDec = 4; | |
int controlDec; //0, 1, 2, 3, or 4 | |
const float controlDecCoarse[] = {0.01, 0.1, 1, 10, 100}; | |
const float controlDecFine[] = {0.001, 0.01, 0.1, 1, 10}; | |
//flash period percentage | |
const int minControlFlash = 0; | |
const int maxControlFlash = 0; | |
int controlFlash; //0 | |
const float controlFlashCoarse[] = {1}; | |
const float controlFlashFine[] = {0.1}; | |
const float flashPercentMin = 0.0; | |
const float flashPercentMax = 10.0; | |
//modes | |
int mode; | |
const int TRIGGER = 0; | |
const int DECADE = 1; | |
const int FLASH = 2; | |
const int numModes = 3; | |
//variables related to hardware inputs | |
float currentFrequency; //hz | |
float currentPeriod; //usec | |
word currentFrequencyTicks; | |
float inputFrequency; //hz | |
float inputPeriod; //usec | |
word inputFrequencyTicks; | |
int inputFrequencyDir; //1 means change was up, 0 mean change was down | |
float currentFlashPercent; | |
float currentFlashPeriod; //usec | |
word currentFlashTicks; | |
float inputFlashPercent; | |
float inputFlashPeriod; //usec | |
word inputFlashTicks; | |
//controls | |
Encoder fineEncoder; | |
int fineChangeFlag; | |
int fineDirFlag; | |
int fineButtonFlag; | |
Encoder coarseEncoder; | |
int coarseChangeFlag; | |
int coarseDirFlag; | |
int coarseButtonFlag; | |
Button decButton; | |
int decButtonFlag; | |
Button modeButton; | |
int modeButtonFlag; | |
//display | |
StrobeDisplay strDisplay; | |
void setup() { | |
//controls | |
fineEncoder.begin(6,5,7); | |
coarseEncoder.begin(3,2,4); //needs to be fixed | |
decButton.begin(8); //needs to be fixed | |
fineChangeFlag= 0; | |
fineDirFlag = 0; | |
fineButtonFlag = 0; | |
coarseChangeFlag = 0; | |
coarseDirFlag = 0; | |
coarseButtonFlag = 0; | |
decButtonFlag = 0; | |
modeButtonFlag = 0; | |
//control firmware | |
controlDec = 0; | |
controlFlash = 0; | |
freqBand = 0; | |
mode = DECADE; | |
//initialize timing variables | |
currentFrequency = 1.0; //hz | |
currentPeriod = (1/currentFrequency)*1000000.0; //usec | |
currentFrequencyTicks = long(inputPeriod/freqBandTick[freqBand]); //use calculateTicks | |
inputFrequency = currentFrequency; //hz | |
inputPeriod = currentPeriod; //usec | |
inputFrequencyTicks = currentFrequencyTicks; | |
currentFlashPercent = 1.0; | |
currentFlashPeriod = (currentFlashPercent/100.0)*currentPeriod; //usec | |
currentFlashTicks = long(currentFlashPeriod/freqBandTick[freqBand]); //use calculateTicks | |
inputFlashPercent = currentFlashPercent; | |
inputFlashPeriod = currentFlashPeriod; //usec | |
inputFlashTicks = currentFlashTicks; | |
//display | |
strDisplay.begin(2); | |
strDisplay.reset(); | |
strDisplay.display(currentFrequency, controlDecCoarse[controlDec], currentFlashPercent, mode); | |
PWM_init(); //PWM Setup | |
} | |
void loop() { | |
readControls(); | |
} | |
void readControls(){ | |
fineEncoder.readEncoder(fineChangeFlag, fineDirFlag, fineButtonFlag); | |
coarseEncoder.readEncoder(coarseChangeFlag, coarseDirFlag, coarseButtonFlag); | |
decButton.readButton(decButtonFlag); | |
modeButton.readButton(modeButtonFlag); | |
//return quickly if nothing has changed | |
if (!fineChangeFlag & !coarseChangeFlag & !fineButtonFlag & !coarseButtonFlag & !decButtonFlag & !modeButtonFlag) return; | |
//update mode NOT IMPLEMENTED | |
if (modeButtonFlag) { | |
incMode(); | |
modeButtonFlag = 0; | |
updateDisplay(); | |
return; | |
} | |
//process based on mode | |
switch (mode) { | |
case TRIGGER: //not implemented | |
break; | |
case DECADE: | |
if (decButtonFlag) { | |
incControlDec(); | |
decButtonFlag = 0; | |
updateDisplay(); | |
} | |
if (coarseChangeFlag) { | |
if (coarseDirFlag) { | |
inputFrequency = currentFrequency + controlDecCoarse[controlDec]; | |
inputPeriod = 1/inputFrequency*1000000.0; | |
inputFrequencyDir = 1; | |
coarseChangeFlag = 0; | |
coarseDirFlag = 0; | |
} else { | |
inputFrequency = currentFrequency - controlDecCoarse[controlDec]; | |
inputPeriod = 1/inputFrequency*1000000.0; | |
inputFrequencyDir = 0; | |
coarseChangeFlag = 0; | |
coarseDirFlag = 0; | |
} | |
} | |
if (fineChangeFlag) { | |
if (fineDirFlag) { | |
inputFrequency = currentFrequency + controlDecFine[controlDec]; | |
inputPeriod = 1/inputFrequency*1000000.0; | |
inputFrequencyDir = 1; | |
fineChangeFlag = 0; | |
fineDirFlag = 0; | |
} else { | |
inputFrequency = currentFrequency - controlDecFine[controlDec]; | |
inputPeriod = 1/inputFrequency*1000000.0; | |
inputFrequencyDir = 0; | |
fineChangeFlag = 0; | |
fineDirFlag = 0; | |
} | |
} | |
if (fineButtonFlag) { | |
inputFrequency = currentFrequency/2.0; | |
inputPeriod = 1/inputFrequency*1000000.0; | |
fineButtonFlag = 0; | |
} | |
if (coarseButtonFlag) { | |
inputFrequency = currentFrequency*2.0; | |
inputPeriod = 1/inputFrequency*1000000.0; | |
coarseButtonFlag = 0; | |
} | |
updateFrequency(); | |
updateFlashPercent(); | |
break; | |
case FLASH: | |
if (coarseChangeFlag) { | |
if (coarseDirFlag) { | |
inputFlashPercent = currentFlashPercent + controlFlashCoarse[controlFlash]; | |
inputFlashPeriod = (inputFlashPercent/100.0)*currentPeriod; | |
coarseChangeFlag = 0; | |
coarseDirFlag = 0; | |
} else { | |
inputFlashPercent = currentFlashPercent - controlFlashCoarse[controlFlash]; | |
inputFlashPeriod = (inputFlashPercent/100.0)*currentPeriod; | |
coarseChangeFlag = 0; | |
coarseDirFlag = 0; | |
} | |
} | |
if (fineChangeFlag) { | |
if (fineDirFlag) { | |
inputFlashPercent = currentFlashPercent + controlFlashFine[controlFlash]; | |
inputFlashPeriod = (inputFlashPercent/100.0)*currentPeriod; | |
fineChangeFlag = 0; | |
fineDirFlag = 0; | |
} else { | |
inputFlashPercent = currentFlashPercent - controlFlashFine[controlFlash]; | |
inputFlashPeriod = (inputFlashPercent/100.0)*currentPeriod; | |
fineChangeFlag = 0; | |
fineDirFlag = 0; | |
} | |
} | |
if (fineButtonFlag) { //ignore control button inputs when adjusting flash percent | |
fineButtonFlag = 0; | |
} | |
if (coarseButtonFlag) { //ignore control button inputs when adjusting flash percent | |
coarseButtonFlag = 0; | |
} | |
updateFlashPercent(); | |
break; | |
} | |
} | |
// Updates the global variables that contain frequency data (based on user input tracking globals): | |
// currentFrequency | |
// currentPeriod | |
// currentFrequncyTicks | |
void updateFrequency() { | |
if (inputFrequency == currentFrequency) return; //return if no change | |
if ((inputFrequency > freqMax) | (inputFrequency < freqMin)) return; //return if out of range | |
//shift to new frequency band if necessary | |
if (inputFrequency > freqBandHigh[freqBand]) raiseFreqBand(); | |
if (inputFrequency < freqBandLow[freqBand]) lowerFreqBand(); | |
//round to closest achievable frequency | |
inputFrequencyTicks = calculateTicks(inputPeriod); | |
//Always shift by one tick at a minimum | |
if (inputFrequencyTicks == currentFrequencyTicks) { | |
if (inputFrequencyDir) inputFrequencyTicks = inputFrequencyTicks - 1; | |
if (!inputFrequencyDir) inputFrequencyTicks = inputFrequencyTicks + 1; | |
} | |
inputFrequencyDir = 0; | |
currentFrequencyTicks = inputFrequencyTicks; | |
currentPeriod = calculatePeriod(currentFrequencyTicks); | |
currentFrequency = 1000000.0/currentPeriod; | |
updateTOP(); | |
updateDisplay(); | |
} | |
// Updates the global variables that contain duty cycle data (based on frequency globals or user input tracking globals) | |
void updateFlashPercent(){ | |
if ((inputFlashPercent > flashPercentMax) || (inputFlashPercent < flashPercentMin)) return; //return if out of range | |
//round to closest achievable tickPeriod | |
inputFlashTicks = calculateTicks((inputFlashPercent/100.0)*currentPeriod); | |
currentFlashTicks = inputFlashTicks; | |
currentFlashPeriod = calculatePeriod(currentFlashTicks); | |
currentFlashPercent = (currentFlashPeriod/currentPeriod)*100.0; | |
updateOFF(); | |
updateDisplay(); | |
} | |
void updateDisplay(){ | |
strDisplay.display(currentFrequency, controlDecCoarse[controlDec], currentFlashPercent, mode); | |
} | |
// Increments the frequency band and updates | |
// approriate control registers and bits | |
void raiseFreqBand(){ | |
freqBand++; | |
if (freqBand > maxFreqBand) freqBand = maxFreqBand; | |
updateTOP(); | |
updateOFF(); | |
updatePrescale(); | |
} | |
// Decrements the frequency band and updates | |
// approriate control registers and bits | |
void lowerFreqBand(){ | |
freqBand--; | |
if (freqBand < minFreqBand) freqBand = minFreqBand; | |
updateTOP(); | |
updateOFF(); | |
updatePrescale(); | |
} | |
// Calculates TOP value based on the currentFrequency | |
// and frequency band and writes it to the OCR1A register | |
void updateTOP(){ | |
OCR1A = calculateTicks(currentPeriod); | |
} | |
// Calculates OFF value based on the currentFrequency, | |
// currentFlashPeriod, and frequency band | |
// and writes it to the OCR1B register | |
void updateOFF(){ | |
OCR1B = calculateTicks(currentFlashPeriod); | |
} | |
// Sets the prescale based on the frequency band | |
// by setting/clearing the appropriate Clock Select bits | |
void updatePrescale(){ | |
switch(freqBandPrescale[freqBand]) { | |
case 256: //prescale = 256 | |
TCCR1B &= ~((1 << CS12) | (1 << CS11) | (1 << CS10)); //clear Clock Select Bits | |
TCCR1B |= (1 << CS12); //set Clock Select Bits | |
break; | |
case 64: //prescale = 64 | |
TCCR1B &= ~((1 << CS12) | (1 << CS11) | (1 << CS10)); //clear Clock Select Bits | |
TCCR1B |= (1 << CS11) | (1 << CS10); //set Clock Select Bits | |
break; | |
case 8: //prescale = 8 | |
TCCR1B &= ~((1 << CS12) | (1 << CS11) | (1 << CS10)); //clear Clock Select Bits | |
TCCR1B |= (1 << CS11); //set Clock Select Bits | |
break; | |
case 1: //prescale = 1 | |
TCCR1B &= ~((1 << CS12) | (1 << CS11) | (1 << CS10)); //clear Clock Select Bits | |
TCCR1B |= (1 << CS10); //set Clock Select Bits | |
break; | |
default: //input is not a valid choice | |
break; | |
} | |
} | |
//Increments the Decade (scale) of the controls | |
void incControlDec(){ | |
controlDec = (controlDec+1)%(maxControlDec+1); //increment or wrap | |
} | |
//Increments the Mode | |
void incMode(){ | |
mode = (mode+1)%numModes; //increment or wrap mode | |
} | |
// Calculates the Ticks in a Time Period based on | |
// the current clock prescale | |
word calculateTicks(float us_period) { | |
return word(round(us_period/freqBandTick[freqBand]-1)); | |
} | |
// Calculates the Period based on Ticks and | |
// the current clock prescale | |
float calculatePeriod(word ticks) { | |
return (ticks+1)*freqBandTick[freqBand]; | |
} | |
// initializes | |
void PWM_init(){ | |
//set TCCR1A and TCCR1B for Non-inverted FAST PWM with OCR1A=TOP (mode 15) | |
//Initially, TCCR1A = TCCR1B = x00 | |
TCCR1A |= (1 << COM1B1) | (1 << COM1B0) | (1 << WGM11) | (1 << WGM10); | |
TCCR1B |= (1 << WGM13) | (1 << WGM12); | |
pinMode(12, OUTPUT); //set DDR for OC1B | |
updateTOP(); //set OCR1A (TOP) | |
updateOFF(); //set OCR1B (OFF) | |
updatePrescale(); //sets prescale and starts the clock | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment