commit a185dc6577db116f6c659426698d3a08d4e920b1
parent 044eb359382d61bcbdbbc605fd4c7194c7ab6b4f
Author: Christos Margiolis <christos@margiolis.net>
Date: Fri, 28 Jan 2022 23:51:49 +0200
lcd working properly
Diffstat:
M | c_embedded/src/main.c | | | 219 | +++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------- |
1 file changed, 147 insertions(+), 72 deletions(-)
diff --git a/c_embedded/src/main.c b/c_embedded/src/main.c
@@ -1,36 +1,32 @@
#define NO_BIT_DEFINES
#include <pic14regs.h>
#include <stdint.h>
-#include <string.h>
+/*#include <string.h>*/
static __code uint16_t __at (_CONFIG) __configword =
_FOSC_HS & _WDTE_OFF & _PWRTE_ON & _LVP_OFF & _WRT_OFF & _BOREN_ON &
_CPD_OFF & _CP_OFF;
+/* MCU related constants */
#define _XTAL_FREQ 16000000 /* Crystal oscillator running at 16MHz */
-#define TIMER_RISING_EDGE (0 << 6) /* Interrupt on rising edge */
-#define TIMER_INTERNAL_CLK (0 << 5) /* Use the CLK0 pin */
-#define TIMER_PRESCALAR_TMR0 (0 << 3) /* Assign prescalar to TMR0 */
+#define TMR0_CLK0 (0 << 5) /* Use the CLK0 pin */
/*
- * The last 3 bits of OPTION_REG indicate the prescalar value. In this case,
+ * Bit 3 assigns the prescalar to TMR0.
+ * Bits 0-2 of OPTION_REG indicate the prescalar value. In this case,
* 111 indicates a prescalar value of 256.
*/
-#define TIMER_PRESCALAR_256 0b111
+#define TMR0_PRESCALAR_256 0b0111
/*
- * We want 1ms delay @ 16Mhz with 256 prescalar, the formula is:
+ * We want 1ms delay @ 16Mhz with 64 prescalar, the formula is:
*
* 256 - ((delay * (fosc / 1000)) / (prescalar * 4)) =
* 256 - ((1 * (16000000 / 1000)) / (256 * 4)) =
- * 256 - ((1 * 16000) / (256 * 4)) =
- * 256 - 15.625 = ~240
+ * 256 - ((1 * 16000) / (256 * 4)) = ~240
*
* sdcc thinks there's an overflow here (hint: he's wrong)...
*/
-#define TIMER_DELAY (256 - ((1 * (_XTAL_FREQ / 1000)) / (256 * 4)))
-#define TIMER_REQ_MAX 3
-
-#define OUTPUT 0
-#define INPUT 1
+#define TMR0_DELAY (256 - ((1 * (_XTAL_FREQ / 1000)) / (256 * 4)))
+#define TMR0_REQ_MAX 3
#define BTN_PORT PORTBbits.RB0
#define BTN_TRIS TRISBbits.TRISB0
@@ -39,18 +35,28 @@ static __code uint16_t __at (_CONFIG) __configword =
#define LED_PORT PORTBbits.RB1
#define LED_TRIS TRISBbits.TRISB1
-#define LCD_RS PORTCbits.RC0
-#define LCD_RW PORTCbits.RC1
-#define LCD_EN PORTCbits.RC2
+#define LCD_RS PORTCbits.RC0 /* Instruction reg: 0, Data reg: 1 */
+#define LCD_RW PORTCbits.RC1 /* Write: 0, Read: 1 */
+#define LCD_EN PORTCbits.RC2 /* Enable read/write */
#define LCD_PORT_DATA PORTD
-#define LCD_SEL_INST 0
-#define LCD_SEL_DATA 1
+#define LCD_PORT_DATA_DIR TRISD
+#define LCD_PORT_CTL_DIR TRISC
+#define LCD_SEL_INST 0 /* Instruction register for RS */
+#define LCD_SEL_DATA 1 /* Data register for RS */
#define LCD_CLEAR 0x01 /* Clear screen */
-#define LCD_CURS_ZERO 0x02 /* Set cursor on (0, 0) */
+#define LCD_CURS_ROW1 0x02 /* Set cursor on (0, 0) */
+#define LCD_CURS_ROW2 0xc0 /* Set cursor on (1, 0) */
#define LCD_CURS_INC 0x06 /* Auto-increment cursor */
#define LCD_CURS_OFF 0x0c /* Hide cursor */
-#define LCD_MODE 0x38 /* 16x2 setup */
-#define LCD_DISPLAY_INIT 0x32 /* Required */
+#define LCD_MODE 0x38 /* 8-bit, 16x2 */
+
+#define OUTPUT 0
+#define INPUT 1
+
+/* Non MCU related constants */
+#define NULL ((void *)0)
+#define BUFSIZ (3 * sizeof(uint32_t))
+
/* Function macros */
#define lcd_putc(c) lcd_data(c, LCD_SEL_DATA)
#define lcd_cmd(cmd) lcd_data(cmd, LCD_SEL_INST)
@@ -58,13 +64,14 @@ static __code uint16_t __at (_CONFIG) __configword =
typedef void (*ev_handler)(void);
struct timer_req {
- ev_handler handler;
- uint32_t rate;
- uint32_t cnt;
+ ev_handler handler; /* ISR callback */
+ uint32_t rate; /* Interval */
+ uint32_t cnt; /* Current time */
};
-static void delay_ms(uint32_t);
+/* Function declarations */
static void tmr0_init(void);
+static void tmr0_delay_ms(uint32_t);
static int tmr0_set_event(ev_handler, uint32_t);
static void tmr0_isr(void) __interrupt;
static void led_blink(void);
@@ -72,45 +79,51 @@ static void button_debounce(void);
static void lcd_init(void);
static void lcd_data(uint8_t, uint8_t);
static void lcd_puts(const char *);
+static void ctx_main(void);
+static void ctx_uptime_maxtp(void);
+static char *itoa(char *, uint32_t);
+static void *memset(void *, int, int);
-static struct timer_req reqs[TIMER_REQ_MAX];
-static uint32_t timecnt = 0; /* Seconds passed since start */
-
-static void
-delay_ms(uint32_t t)
-{
- while (t--)
- __asm nop __endasm;
-}
+/* Global variables */
+static struct timer_req reqs[TMR0_REQ_MAX];
+static uint32_t timecnt = 0; /* Seconds passed since start */
+static int f_ctx = 0; /* Change context */
+static uint8_t humid = 0; /* Current humidity */
+static int8_t tp = 0; /* Current temperature */
+static int8_t maxtp = 0; /* Max temperature */
+static char buf[BUFSIZ+1] = {0}; /* Generic buffer */
+/* Function implementations */
static void
tmr0_init(void)
{
- struct timer_req *r;
- uint8_t i;
-
- for (i = 0; i < TIMER_REQ_MAX; i++) {
- r = &reqs[i];
- r->handler = NULL;
- r->rate = 0;
- r->cnt = 0;
- }
+ memset(reqs, 0, sizeof(reqs));
OPTION_REG = 0;
- OPTION_REG |= TIMER_INTERNAL_CLK | TIMER_RISING_EDGE |
- TIMER_PRESCALAR_TMR0 | TIMER_PRESCALAR_256;
- TMR0 = TIMER_DELAY;
+ OPTION_REG |= TMR0_CLK0 | TMR0_PRESCALAR_256;
+ TMR0 = TMR0_DELAY;
INTCONbits.TMR0IE = 1; /* TMR0 Interrupt Enable */
INTCONbits.GIE = 1; /* Global Interrupt Enable */
INTCONbits.PEIE = 1; /* Peripheral Interrupt Enable */
}
+static void
+tmr0_delay_ms(uint32_t t)
+{
+ while (t--) {
+ while (INTCONbits.TMR0IF == 0)
+ ; /* nothing */
+ INTCONbits.TMR0IF = 0;
+ TMR0 = TMR0_DELAY;
+ }
+}
+
static int
tmr0_set_event(ev_handler handler, uint32_t rate)
{
struct timer_req *r;
uint8_t i;
- for (i = 0; i < TIMER_REQ_MAX; i++) {
+ for (i = 0; i < TMR0_REQ_MAX; i++) {
r = &reqs[i];
if (r->handler != NULL)
continue;
@@ -130,7 +143,7 @@ tmr0_isr(void) __interrupt
if (INTCONbits.TMR0IF != 1)
return;
- for (i = 0; i < TIMER_REQ_MAX; i++) {
+ for (i = 0; i < TMR0_REQ_MAX; i++) {
r = &reqs[i];
if (r->handler == NULL)
continue;
@@ -139,7 +152,7 @@ tmr0_isr(void) __interrupt
r->cnt = 0;
}
}
- TMR0 = TIMER_DELAY;
+ TMR0 = TMR0_DELAY;
INTCONbits.TMR0IF = 0; /* Clear interrupt flags */
}
@@ -149,12 +162,11 @@ led_blink(void)
LED_PORT ^= 1;
/*
* Increment here since this function is called every 1 sec.
- * No need to create another one.
+ * No need to create another timer callback.
*/
timecnt++;
}
-
static void
button_debounce(void)
{
@@ -162,45 +174,43 @@ button_debounce(void)
/* Button is pressed */
if (BTN_PORT == 0) {
- if (cnt == 0)
+ if (cnt == 0) {
+ /* Actual button functionality goes here. */
+ f_ctx = 1;
cnt++;
+ }
cnt = BTN_DEBOUNCE_TIME_MS;
- } else if (cnt != 0)
+ } else if (cnt != 0) {
cnt--;
+ f_ctx = 0;
+ }
}
-/* FIXME: fix delays */
static void
lcd_init(void)
{
- LCD_PORT_DATA = 0;
+ LCD_PORT_CTL_DIR = OUTPUT;
+ LCD_PORT_DATA_DIR = OUTPUT;
LCD_RS = 0;
LCD_RW = 0;
LCD_EN = 0;
- TRISC = OUTPUT;
- TRISD = OUTPUT;
- lcd_cmd(LCD_DISPLAY_INIT);
- delay_ms(150);
- lcd_cmd(LCD_DISPLAY_INIT);
- delay_ms(150);
-
lcd_cmd(LCD_MODE);
+ tmr0_delay_ms(15);
+ lcd_cmd(LCD_CURS_ROW1);
+ lcd_cmd(LCD_CURS_OFF);
lcd_cmd(LCD_CURS_INC);
- lcd_cmd(LCD_CURS_ZERO);
lcd_cmd(LCD_CLEAR);
- lcd_cmd(LCD_CURS_OFF);
}
-/* FIXME: fix delays */
static void
lcd_data(uint8_t c, uint8_t rs)
{
LCD_RS = rs;
LCD_RW = 0;
- LCD_EN = 1;
LCD_PORT_DATA = c;
- delay_ms(500);
+ LCD_EN = 1;
+ tmr0_delay_ms(2);
LCD_EN = 0;
}
@@ -211,20 +221,85 @@ lcd_puts(const char *str)
lcd_putc(*str++);
}
+/* Helper to clean up the code below */
+#define LCD_PUTS_BUF(buf, v) do { \
+ memset(buf, 0, sizeof(buf)); \
+ lcd_puts(itoa(&buf[sizeof(buf)-1], v)); \
+} while (0)
+
+static void
+ctx_main(void)
+{
+ lcd_cmd(LCD_CURS_ROW1);
+ lcd_puts("19390133");
+
+ lcd_cmd(LCD_CURS_ROW2);
+ LCD_PUTS_BUF(buf, tp);
+ lcd_puts("\337C ");
+
+ LCD_PUTS_BUF(buf, humid);
+ lcd_puts("%");
+}
+
+static void
+ctx_uptime_maxtp(void)
+{
+ lcd_cmd(LCD_CURS_ROW1);
+ lcd_puts("T: ");
+ LCD_PUTS_BUF(buf, timecnt);
+
+ lcd_cmd(LCD_CURS_ROW2);
+ lcd_puts("Max: ");
+ LCD_PUTS_BUF(buf, maxtp);
+ lcd_puts("\337C");
+}
+
+#undef LCD_PUTS_BUF
+
+/*
+ * To avoid reversing the string, the caller has to provide a pointer to the
+ * end of the string.
+ */
+static char *
+itoa(char *s, uint32_t n)
+{
+ *s = '\0';
+ if (n == 0)
+ *--s = '0';
+ for (; n; n /= 10)
+ *--s = n % 10 + '0';
+ return (s);
+}
+
+static void *
+memset(void *dst, int v, int len)
+{
+ uint8_t *dst0;
+
+ dst0 = dst;
+ while (len--)
+ *dst0++ = v;
+ return (dst);
+}
+
void
main(void)
{
tmr0_init();
- tmr0_set_event(&led_blink, 1000); /* Blink every 1 sec */
+ tmr0_set_event(&led_blink, 1000);
tmr0_set_event(&button_debounce, 1);
lcd_init();
- lcd_cmd(LCD_CURS_ZERO);
- lcd_puts("19390133");
BTN_TRIS = INPUT;
- LED_PORT = 1; /* LED on */
+ LED_PORT = 0; /* LED on */
LED_TRIS = OUTPUT;
for (;;) {
+ lcd_cmd(LCD_CLEAR);
+ if (!f_ctx)
+ ctx_main();
+ else
+ ctx_uptime_maxtp();
+ tmr0_delay_ms(1000);
}
}