Skip to content

Instantly share code, notes, and snippets.

@ajarmst
Created February 13, 2024 15:23
Show Gist options
  • Save ajarmst/900ddcdfcc6880065bf0e5830380275c to your computer and use it in GitHub Desktop.
Save ajarmst/900ddcdfcc6880065bf0e5830380275c to your computer and use it in GitHub Desktop.
// this demo is specifically set to run on the R1.0 ATmega328PB Proto PCB
// and the R1.8 'Sweet Sensor Suite' boards.
// demo board is using a 12MHz XTAL with the DIV8 fuse cleared, so... 12MHz
// to operate this demo set the bus rate for your device correctly
#define F_CPU 12E6
// the accelerometer and i/o chip both use interrupts that this demo use
// accelerometer is configured to interrupt on tap (used to wakeup the OLED)
// i/o configured to interrupt on pin change
// this demo uses floating point output, so the project needs to be configured
// for floating point support as directed in the course notes
// ssd1306 library header selects 128x32 option
// you need to modify the SSD1306 header to option match your display size
// this demo is specifically setup to work with the following connections:
// I/O Board Atmega328PB
// -------------------------
// SCL SCL (PC5)
// SDA SDA (PC4)
// L0 PC3 (configured as an output)
// AI1 PC2 (PCINT10 [PCI1], configured as an input, with interrupt)
// UT RXD (PD0)
// UR TXD (PD1)
// I/O Int PD2 (PCINT18 [PCI2], configured as an input, with interrupt)
// Buz PD6 (0C0A PWM, configured as an output)
// the main micro uses power from the sensor board
// so the USBC connection is not used on the main board
#include <avr/io.h>
#include <util/delay.h> // have to add, has delay implementation (requires F_CPU to be defined)
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h> // definitions to place items in flash
#include <stdio.h>
#include "sci.h"
#include "timer.h"
#include "I2C.h"
#include "LM75A.h"
#include "SSD1306.h"
#include "atd.h"
#include "veml7700.h"
#include "adxl343.h"
#include "MCP23008.h"
#include "bme280.h"
#include "misc.h"
// constants for timer output compare offset, init and ISR rearm
// program activities are coordinated by 100ms tick intervals
// and interrupts from sensors
const unsigned int _Timer_OC_Offset = 18750; // 1 / (12000000 / 64 / 18750) = 100ms (w/prescale 64)
#define _ms_per_tick 100
const unsigned int C_SPLASH_SCREEN_ON_TIME = 1000 / _ms_per_tick;
// global isr-modified 100ms tick counter
// as a ulong this means the timer will wrap after 136 years, so should be OK
volatile unsigned long _Ticks = 0;
// ISR-modified flag that checks interrupt pin from accelerometer (activity)
volatile unsigned char _AccActivity = 0;
// ISR-modified flag that checks interrupt pin from port expander (pin change)
volatile unsigned char _PortActivity = 0;
// if _Ticks is higher than this value, the OLED should be off
// in other words, the OLEDARM value projects into the future for OLED on time
unsigned long _OLEDARM = 0;
unsigned char _OLEDState = 0; // current state of OLED (prevents redundant on/off calls in logic)
// toggle value to control OLED inversion to prevent pixel wear
unsigned char InverseCount = 0;
// logic to non-redundantly turn on/off OLED
void OLED_ONOFFControl (void);
// local display functions (OLED and/or USART)
// show A/D value on OLED
void ShowAD (void);
// show devices found on the I2C bus
void ShowBusScan (void);
// show LM75AD,118 temp on OLED
void ShowTemp (void);
// show ambient light level from VEML7700
void ShowAmbientLight (int OnSCI, int OnOLED);
// splash screen data, placed in flash (program memory)
// this pattern may be generated directly with the 'OLED Edit' utility on Moodle
const char _SplashMap [512] PROGMEM =
{
/* Page 0: */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* Page 1: */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x19, 0xf9, 0xf9, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf0, 0x7c, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x00,
0xc0, 0xe0, 0x70, 0x38, 0x18, 0x18, 0x18, 0x38, 0x70, 0xf0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x70, 0x30, 0x18,
0x18, 0x18, 0x38, 0xf0, 0xc0, 0x00, 0x00, 0xc0, 0xe0, 0x70, 0x38, 0x18, 0x18, 0x18, 0x38, 0x70,
0xf0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x18, 0x18, 0x18, 0x18, 0x38, 0xf0, 0xe0, 0x00,
0x00, 0x00, 0xf8, 0xf8, 0x60, 0x30, 0x18, 0x18, 0x18, 0x38, 0xf0, 0xe0, 0x00, 0x00, 0xc0, 0xe0,
0x70, 0x38, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* Page 2: */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x60, 0x60, 0x7f, 0x7f, 0x60, 0x60, 0x60,
0x00, 0x00, 0x00, 0x00, 0xc0, 0xf0, 0x3e, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0f, 0x3f, 0x38, 0x70, 0x60, 0x60, 0x60, 0x70, 0x38, 0x1f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x7f, 0x60, 0x60, 0x60,
0x60, 0x70, 0x38, 0x1f, 0x0f, 0x00, 0x00, 0x0f, 0x3f, 0x38, 0x70, 0x60, 0x60, 0x60, 0x70, 0x38,
0x1f, 0x0f, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x67, 0x63, 0x63, 0x63, 0x73, 0x33, 0x7f, 0x7f, 0x00,
0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x3f,
0x70, 0x60, 0x60, 0x60, 0x30, 0x18, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* Page 3: */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
// one-time inits for the program, broken out to shorten main
void DoOneTimeInits (void)
{
// only required for other XTAL configurations, in this version 12MHz is fine
// for no XTAL/16MHz hardware configurations, adjustments will be required to the code
// jump up to 8MHz, as 2MHz is a little slow for the OLED (works, just is not great performance)
// 11.11.2 ATmega328PB Full
//CLKPR = 0b10000000; // enable changes
//CLKPR = 0b00000001; // set to div by 2 (16 / 2 = 8MHz) max at 3.3V is higher (12MHz?)
// bring up the UART, specify clock and desired BAUD rate
// while vcomm and pc handle much higher rates, BAUD rate generation
// does not work out well above 38400 at 12MHz (actually 12MHz / 16)
// no fractional baud rate on this chip - 'tis but a simple UART
SCI0_Init(F_CPU, 38400, 0);
// welcome message, so we know it booted OK
SCI0_TxString("\x1b[2J\x1b[1;1HATmega328PB Up! Demo for I/O 1.8 + ATmega328PB Proto PCB!\x1b[0K");
// informational - platform
//{
//char buff [80] = {0};
//(void)sprintf (buff, "\r\nsize of char %d", sizeof (char));
//SCI0_TxString(buff);
//(void)sprintf (buff, "\r\nsize of short %d", sizeof (short));
//SCI0_TxString(buff);
//(void)sprintf (buff, "\r\nsize of int %d", sizeof (int));
//SCI0_TxString(buff);
//(void)sprintf (buff, "\r\nsize of long %d", sizeof (long));
//SCI0_TxString(buff);
//(void)sprintf (buff, "\r\nsize of long long %d", sizeof (long long));
//SCI0_TxString(buff);
//(void)sprintf (buff, "\r\nsize of float %d", sizeof (float));
//SCI0_TxString(buff);
//(void)sprintf (buff, "\r\nsize of double %d", sizeof (double));
//SCI0_TxString(buff);
//}
// setup GPIO pin PC2 for interrupt (for accelerometer)
// int10 is part of PCI1 group of pins
PCMSK1 |= 0b00000100; // turn on PCINT10 pin mask (enable interrupts) (12.2.7)
PCICR |= 0b00000010; // turn on interrupts for group 1 (12.2.4)
// using PC2 as AI1 (accelerometer, interrupt 1)
DDRC &= ~0b000000100; // make PC2 an input (default)
// setup GPIO pin PD2 for interrupt (for port expander)
// int18 is part of PCI2 group of pins
PCMSK2 |= 0b00000100; // turn on PCINT18 pin mask (enable interrupts) (13.2.6)
PCICR |= 0b00000100; // turn on interrupts for group 2 (13.2.4)
// using PD2 as IOI (i/o port expander interrupt)
DDRD &= ~0b00000100; // make PD2 an input (default)
// using PC3 for i/o board LED
DDRC |= 0b00001000; // make PC3 an output
// using PD6 (0C0A) as PWM output
DDRD |= 0b01000000; // make PD6 an output
// bring up the timer, requires ISR!
Timer_Init(Timer_Prescale_64, _Timer_OC_Offset); // 100ms intervals
// enable sleep mode, for idle, sort of similar to WAI on 9S12X (13.2)
sleep_enable();
// bring up the I2C bus, at 400kHz operation
I2C_Init(F_CPU, I2CBus400);
// dump bus scan info to the SCI (helpful if the bus is connected to
// other devices, and you want to know what the address is)
ShowBusScan ();
// bring up the OLED module (orientation flipped)
SSD1306_DispInit(SSD1306_OR_UP);
// show splash screen test
for (int i = 0; i < 4; ++i)
{
SSD1306_SetPage(i, &_SplashMap[i * 128]);
}
// render splash screen
SSD1306_Render();
// arm the display to be on for at least 2s initially
_OLEDARM = _Ticks + 2000 / _ms_per_tick;
// while we are looking at splash screen...
// bring up ambient light sensor
if (VEML7700_Init())
{
SCI0_TxString("\x1b[3;1HVEML7700 Unexpected error in init!\x1b[0K");
}
// bring up ADXL343
if (!ADXL343_Init())
{
//SCI0_TxString("\r\nADXL343 Up!");
// accelerometer can be configured to interrupt on many different conditions
// in this case, we want interrupt for activity, routed to interrupt output 1
ADXL343_ActivityInterrupt();
}
else
{
SCI0_TxString("\x1b[3;1HADXL343 Unexpected error in init!\x1b[0K");
}
// bring up the BME280
{
if (BME280_Init())
{
SCI0_TxString("\x1b[3;1HBME280 Unexpected error in init!\x1b[0K");
}
else
{
if (BME280_FetchCompensationValues())
{
SCI0_TxString("\x1b[3;1HUnable to load BME280 compensation values!\x1b[0K");
}
else
{
if (BME280_SetOversampling(BME280_OS_1x, BME280_OS_1x, BME280_OS_1x, BME280_ModeNormal))
{
SCI0_TxString("\x1b[3;1HUnable to set BME280 oversampling rates and operating mode!\x1b[0K");
}
}
}
}
// set port expander input pins as weak pull-ups (except the one tied to a pull-up button)
MCP23008_SetWeakPullups(0b11111110);
// set the MCP23008 to interrupt on pin 0 (connected to a pull-up switch in test circuit)
MCP23008_SetInterrupt(0b00000001);
// bring up A/D channel 0, because why not?
//AtoD_Init(AtoD_Channel_0);
// setup PWM
Timer_F_PWM0(Timer_PWM_Channel_OC0A, Timer_PWM_ClockSel_Div64, Timer_PWM_Pol_NonInverting, 0);
// enable interrupts
sei();
}
int main(void)
{
DoOneTimeInits ();
// local control: is the splash screen done? default no
int iSplashDone = 0;
// the standard "don't leave me!" loop
while (1)
{
// go idle!
// this will now fall through on:
// a pin interrupt (activity on the accelerometer)
// I/O interrupt (activity on the port expander)
// a timer interrupt
sleep_cpu();
// toggle LED for proof of timer life
PINC = 0b00001000;
// check to see if the accelerometer has triggered an interrupt (activity)
// if so, arm the display for on time
if (_AccActivity)
{
_AccActivity = 0;
// clear the interrupt
ADXL343_ReadInterruptSource();
// activity detected on the accelerometer, so rearm the OLED to go on X amount of time
_OLEDARM = _Ticks + 5000 / _ms_per_tick;
{
char buff [80] = {0};
TimeFromMS (buff, _Ticks * _ms_per_tick);
SCI0_TxString ("\x1b[1;1HAccelerometer wake up detected at ");
SCI0_TxString (buff);
SCI0_TxString ("\x1b[0K");
}
}
// check to see if the port expander has triggered an interrupt (pin change)
// if so, clear the interrupt, and write the port value to the terminal
if (_PortActivity)
{
_PortActivity = 0;
unsigned char portval = 0;
MCP23008_ReadINTCap (&portval);
char buff[80] = {0};
(void)sprintf (buff, "\x1b[2;1HPort interrupt detected : 0x%2.2X at ", portval);
SCI0_TxString(buff);
TimeFromMS (buff, _Ticks * _ms_per_tick);
SCI0_TxString(buff);
SCI0_TxString ("\x1b[0K");
}
// only update OLED after splash screen is done (not super efficient once the timeout is done (extra checks))
// if the splash timeout is done, clear the display, mark as done
if (!iSplashDone && _Ticks > C_SPLASH_SCREEN_ON_TIME)
{
iSplashDone = 1;
SSD1306_Clear();
_Ticks = 0;
// one-time rendering items here (to replace constant trim for output)
{
SCI0_TxString ("\x1b[5;1HBME280");
SCI0_TxString ("\x1b[6;1H------");
SCI0_TxString ("\x1b[5;40HADXL343");
SCI0_TxString ("\x1b[6;40H-------");
SCI0_TxString ("\x1b[11;1HVEML7700");
SCI0_TxString ("\x1b[12;1H--------");
SCI0_TxString ("\x1b[11;40HLM75AD");
SCI0_TxString ("\x1b[12;40H-----");
// kill speaker chirp
Timer_F_PWM0(Timer_PWM_Channel_OC0A, Timer_PWM_ClockSel_STOP, Timer_PWM_Pol_NonInverting, 0);
}
}
// long intervals (see note below)
if (!(_Ticks % (60000 / _ms_per_tick)) && iSplashDone)
{
SSD1306_SetInverse((++InverseCount) % 2);
}
// I2C bus reads here, always show on SCI
// only show on OLED if splash done, and state is armed
{
// general buffer for screen/terminal output
char buff [100] = { 0 };
int iX = 0, iY = 0, iZ = 0;
float gx = 0, gy = 0, gz = 0;
if (!ADXL343_ReadRegAccData (&iX, &iY, &iZ))
{
gx = iX * 0.0039;
gy = iY * 0.0039;
gz = iZ * 0.0039;
(void)sprintf (buff, "\x1b[7;40HX:%6.2f\x1b[0K", gx);
SCI0_TxString(buff);
(void)sprintf (buff, "\x1b[8;40HY:%6.2f\x1b[0K", gy);
SCI0_TxString(buff);
(void)sprintf (buff, "\x1b[9;40HZ:%6.2f\x1b[0K", gz);
SCI0_TxString(buff);
}
else
{
SCI0_TxString("\x1b[3;1HADXL343 error...");
}
// OLED updates, skipped if OLED is off (who will see these changes?)
if (iSplashDone && _OLEDState)
{
// show runtime on OLED
TimeFromMS (buff, _Ticks * _ms_per_tick);
SSD1306_StringXY(0, 0, buff);
// show LM75AD,118 temp on OLED
ShowTemp ();
// show A/D value from channel 0
//ShowAD ();
//
// show ambient light level
ShowAmbientLight (1, 1);
// show accelerometer data
{
(void)sprintf (buff, "X:%6.2f Y:%6.2f", gx, gy);
SSD1306_StringXY (0, 3, buff);
(void)sprintf (buff, "Z:%6.2f", gz);
SSD1306_StringXY (12, 2, buff);
}
// show the data from the BME280 sensor
{
// 0 1 2 3 4 5 6 7
// PMSB PLSB PXLSB TMSB TLSB TXLSB HMSB HSLB
//long temp = BME_compensate_T_int32 (adcT);
//long temp = compensate_temperature (adcT);
uint32_t rawT = BME280_raw_T ();
int32_t compT = BME280_compensate_T_int32 (rawT);
uint32_t rawH = BME280_raw_H();
uint32_t compH = BME280_compensate_H_int64 (rawH);
uint32_t rawP = BME280_raw_P ();
uint32_t compP = BME280_compensate_P_int32 (rawP);
char buff[80] = {0};
(void)sprintf (buff, "\x1b[7;1HTemp = %0.2fC ", compT / 100.0f);
SCI0_TxString(buff);
(void)sprintf (buff, "\x1b[8;1HHumidity = %0.2frH ", compH / 1024.0f);
SCI0_TxString(buff);
(void)sprintf (buff, "\x1b[9;1HPressure = %0.2fhPa ", (compP + 7735) / 100.0f);
SCI0_TxString(buff);
}
}
}
// render any changes, turn on/off as timing indicates
SSD1306_Render();
OLED_ONOFFControl();
}
}
void ShowAmbientLight (int OnSCI, int OnOLED)
{
char buff [80] = {0};
// show ambient light level
{
unsigned int ambientLevel = 0;
if (!VEML7700_ReadAmbient(&ambientLevel))
{
if (OnSCI)
{
(void)sprintf(buff, "\x1b[13;1HAmbient: %4.4X (%0.1f%%) ", ambientLevel, (float)ambientLevel / 0xFFFF * 100);
SCI0_TxString(buff);
}
if (OnOLED)
{
(void)sprintf (buff, "Amb L: %4.4X", ambientLevel);
SSD1306_StringXY (0, 2, buff);
}
}
else
{
SCI0_TxString("\x1b[3;1Error reading VEML7700!");
}
}
}
void ShowTemp (void)
{
char buff [80] = {0};
(void)sprintf (buff, "\x1b[13;40H%5.1fC ", LM75A_GetTempF());
SCI0_TxString (buff);
// OLED: show temperature (requires LM75A to be on the I2C bus)
(void)sprintf (buff, "T: %5.1f\x1F", LM75A_GetTempF());
SSD1306_StringXY(0, 1, buff);
}
void ShowBusScan (void)
{
unsigned char scanresults [128] = {0};
char buff [80] = {0};
I2C_Scan(scanresults);
SCI0_TxString ("\x1b[3;1HI2C Bus Scan (7-bit addr): ");
for (int i = 0; i < 128; ++i)
{
if (scanresults[i])
{
(void)sprintf (buff, "%2.2X, ", i);
SCI0_TxString(buff);
}
}
SCI0_TxString(" done");
}
void ShowAD (void)
{
char buff [80] = {0};
//SCI0_TxString("\x1b[33m");
unsigned char AD_low = ADCL; // must be read first
unsigned char AD_high = ADCH;
// UART:
//(void)sprintf (buff, " A/D Channel 0 : 0x%3.3X", AD_low + AD_high * 256);
//SCI0_TxString(buff);
//SCI0_TxString("\x1b[0m");
// OLED:
(void)sprintf (buff, "A/D: %3.3X", AD_low + AD_high * 256);
SSD1306_StringXY (13, 1, buff);
}
void OLED_ONOFFControl (void)
{
// OLED on/off logic
if (_OLEDARM >= _Ticks)
{
// OLED should be ON
if (!_OLEDState)
{
_OLEDState = 1;
SSD1306_DisplayOn();
}
}
else
{
// OLED should be OFF
if (_OLEDState)
{
_OLEDState = 0;
SSD1306_DisplayOff();
}
}
}
// output compare A interrupt
ISR(TIMER1_COMPA_vect)
{
// rearm the output compare operation
OCR1A += _Timer_OC_Offset; // 100ms intervals @ prescale 64
// count 100ms ticks!
++_Ticks;
}
//ISR (TIMER0_OVF_vect)
//{
//OCR0A = 128;
//}
// this interrupt is hooked up to the accelerometer interrupt 1 line
// and will respond to any edge change (accelerometer configured to interrupt on activity)
ISR (PCINT1_vect)
{
// flag is cleared automatically, so just need to take action
// accelerometer activity interrupt
// only arm if this is a rising edge of the interrupt
if (PINC & 0b00000100)
{
// arm activity indicator
_AccActivity = 1;
// show on the LED that the interrupt has flagged
// when main loop sees the flag it will clear it
//PORTC |= 0b00001000;
}
}
// this interrupt is hooked up to the port expander interrupt line
ISR (PCINT2_vect)
{
// flag is cleared automatically, so just need to take action
// only arm if this is a rising edge of the interrupt (not sure if this is OK)
//if (PIND & 0b00000100)
unsigned char stuff = PIND; //(is this necessary?)
stuff++; // suppress warning
{
// show on the LED that the interrupt has flagged
// when main loop sees the flag it will clear it
PORTC |= 0b00001000;
// mark as port changed
_PortActivity = 1;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment