// by Ido Gendel, 2020
// Share and enjoy!
#include <SI_EFM8BB1_Register_Enums.h>
char msg[] = "Hello World! \n"; // Includes room for numbers
const uint8_t lastDigitPos = 19;
volatile char *cp;
// Do not read directly - use millis()
volatile uint32_t _millis = 0;
const uint8_t DEBOUNCE_MS = 10;
volatile uint8_t debounceMSLeft;
uint8_t oldButtonState = 1;
// This function is called immediately after reset, in SILABS_STARTUP.A51
void SiLabs_Startup (void) {
// Disable watchdog
WDTCN = 0xDE;
WDTCN = 0xAD;
}
uint32_t millis(void) {
uint32_t result;
IE_EA = 0; // Disable interrupts
result = _millis;
IE_EA = 1; // Re-enable interrupts
return result;
}
void setup(void) {
P1MDOUT |= P1MDOUT_B4__PUSH_PULL; // Set built-in LED pin (P1.4) to push-pull output
// Built-in button pin (P0.2) digital input by default
// Weak pull-ups enabled by default.
P0_B2 = 1;// Turn WPU on for button input
// Default clock is internal 24.5MHz div 8
// As a default, timers 0/1 uses system clock div 12 prescaler
TMOD |= TMOD_T1M__MODE2; // Set Timer1 mode to 8-bit auto-reload
TH1 = 243; // Set reload value to produce OVF @19.2KHz
TCON_TR1 = 1; // Enable timer1
TMOD |= TMOD_T0M__MODE1; // Set Timer0 mode to 16-bit
TH0 = 0xFF; // Set Timer0 counter to overflow after 255 "ticks"
TL0 = 0x01;
TCON_TR0 = 1; // Enable timer0
// Enable UART in crossbar; TX pin (P0.4) will become output automatically
XBR0 |= XBR0_URT0E__ENABLED;
// Enable crossbar
XBR2 = 0x40;
IE_ET0 = 1; // Enable timer0 interrupt
IE_ES0 = 1; // Enable UART0 interrupt
IE_EA = 1; // Enable interrupts globally
}
void populateSecondsText(void) {
uint8_t i = lastDigitPos;
uint32_t s = millis() / 1000;
do {
msg[i--] = s % 10 + 48;
s = s / 10;
} while (s > 0);
}
int main (void) {
setup();
for ( ; ; ) {
if ((0 == debounceMSLeft) && (P0_B2 != oldButtonState)) {
debounceMSLeft = DEBOUNCE_MS;
oldButtonState = P0_B2;
if (P0_B2) {
P1_B4 = 0; // LED ON
populateSecondsText();
cp = &msg[1];
SBUF0 = msg[0]; // Start UART transmission
}
}
}
}
SI_INTERRUPT (TIMER0_OVF_ISR, TIMER0_IRQn) {
// Interrupt flag is cleared automatically
TH0 = 0xFF; // Reload counter value
TL0 = 0x01;
++_millis;
if (debounceMSLeft) {
--debounceMSLeft;
}
}
SI_INTERRUPT (UART0_ISR, UART0_IRQn) {
// Transmit interrupt flag must be cleared in firmware:
SCON0_TI = 0;
// Anything left to transmit? (assuming null-terminated string)
if (0 != *cp) {
SBUF0 = *cp++;
} else {
P1_B4 = 1; // LED OFF
}
}
Comments