commit 57c9c092e7cebd82c55d3e204cfc087a0d2d61e2
parent a185dc6577db116f6c659426698d3a08d4e920b1
Author: Christos Margiolis <christos@margiolis.net>
Date: Wed, 2 Feb 2022 07:31:23 +0200
almost done, gotta minimize code
Diffstat:
25 files changed, 814 insertions(+), 240 deletions(-)
diff --git a/c_embedded/doc/bme280_datasheet.pdf b/c_embedded/doc/bme280_datasheet.pdf
Binary files differ.
diff --git a/c_embedded/doc/doc.pdf b/c_embedded/doc/doc.pdf
Binary files differ.
diff --git a/c_embedded/doc/doc.tex b/c_embedded/doc/doc.tex
@@ -0,0 +1,133 @@
+\documentclass{article}
+\usepackage[utf8]{inputenc}
+\usepackage[greek,english]{babel}
+\usepackage{alphabeta}
+\usepackage{fancyhdr}
+\usepackage{listings}
+\usepackage{mathtools}
+\usepackage{xcolor}
+\usepackage{graphicx}
+\usepackage{siunitx}
+\usepackage{float}
+
+\title{Ενσωματωμένα Συστήματα - Τελική Εργασία}
+\author{Χρήστος Μαργιώλης - 19390133}
+\date{Ιανουάριος 2022}
+
+\begin{document}
+
+\begin{titlepage}
+ \maketitle
+ \begin{figure}[t!]
+ \begin{center}
+ \includegraphics[scale=0.3]{./res/uniwalogo.png} \\
+ \Large
+ \textbf{Πανεπιστήμιο Δυτικής Αττικής} \\
+ \large
+ Τμήμα Μηχανικών Πληροφορικής και Ηλεκτρονικών Υπολογιστών
+ \end{center}
+ \end{figure}
+\end{titlepage}
+
+\renewcommand{\contentsname}{Περιεχόμενα}
+\tableofcontents
+\pagebreak
+
+\section{Πληροφορίες}
+\subsection{Λίστα υλικών -- BOM}
+\begin{itemize}
+ \item Microchip PIC16F877A - I/P μικροελεγκτής.
+ \item Adafruit BME280 σένσορας θερμοκρασίας, υγρασίας και πίεσης.
+ \item 16x2 LCD οθόνη.
+ \item 1x \SI{16}{\mega\hertz} κρυσταλλικός ταλαντωτής.
+ \item 2x \SI{10}{\kohm} αντίσταση.
+ \item 2x \SI{330}{\ohm} αντίσταση.
+ \item 1x \SI{10}{\kohm} ποτενσιόμετρο.
+ \item 2x \SI{22}{\pico\farad} κεραμεικός πυκωντής.
+ \item 2x LED
+ \item 2x κουμπί.
+ \item Καλώδια.
+ \item 3x AAA μπαταρίες (4.5V) ή μπαταρία 9V με 5V διαιρέτη τάσης.
+\end{itemize}
+
+\subsection{Κόστος παραγωγής}
+
+Οι τιμές υπολογίστηκαν με βάση τα τιμολόγια του https://www.digikey.com. \\
+
+Για 100 τεμάχια:
+\begin{center}
+\begin{tabular}{|l|l|}
+ \hline
+ \textbf{Μέρος} & \textbf{Τιμή} \\
+ \hline
+ PIC16F877A & \$706 \\
+ BME280 & \$1495 \\
+ LCD & \$365 \\
+ \hline
+ Σύνολο & \$2566 \\
+ \hline
+\end{tabular}
+\end{center}
+
+Για 1500 τεμάχια:
+\begin{center}
+\begin{tabular}{|l|l|}
+ \hline
+ \textbf{Μέρος} & \textbf{Τιμή} \\
+ \hline
+ PIC16F877A & \$10.590 \\
+ BME280 & \$22.420 \\
+ LCD & \$5.470 \\
+ \hline
+ Σύνολο & \$38.480 \\
+ \hline
+\end{tabular}
+\end{center}
+
+'Οχι και ό,τι πιο οικονομικό έχει βγει...
+
+\subsection{Θερμοκρασίες λειτουργίας}
+
+\begin{center}
+\begin{tabular}{|l|l|}
+ \hline
+ \textbf{Μέρος} & \textbf{Εύρος θερμοκρασίας} \\
+ \hline
+ PIC16F877A & $\SI{-40}{\celsius} \sim \SI{85}{\celsius}$ \\
+ BME280 & $\SI{-40}{\celsius} \sim \SI{85}{\celsius}$ \\
+ LCD & $\SI{-20}{\celsius} \sim \SI{70}{\celsius}$ \\
+ \hline
+\end{tabular}
+\end{center}
+
+Οπότε, παίρνοντας υπόψη την οθόνη LCD η οποία έχει το μικρότερο
+εύρος θερμοκρασίας λειτουργίας, το σύστημα είναι ασφαλές να
+λειτουργήσει στους $\SI{-20}{\celsius} \sim \SI{70}{\celsius}$.
+
+\subsection{Διάρκεια ζωής}
+
+<++>
+
+\section{Ανάπτυξη συστήματος}
+\subsection{Εργαλεία}
+Η ανάπτυξη του συστήματος έγινε σε FreeBSD 13.0 με την χρήση του
+\lstinline{sdcc} C compiler, και το \lstinline{pk2cmd} για την
+επικοινωνία του μικροελεγκτή με το PICKit2 -- τον προγραμματιστή.
+'Εχω αναλύσει την διαδικασία αυτή σε μορφή οδηγού στην ιστοσελίδα
+μου και στο FreeBSD Wiki: https://wiki.freebsd.org/Microcontrollers/PIC
+
+\subsection{Σχηματικό}
+\begin{center}
+ \includegraphics[width=\linewidth]{./res/schem.png}
+\end{center}
+
+\subsection{PCB}
+<++>
+
+\subsection{Κώδικας}
+<++>
+
+\subsection{Εικόνες}
+<++>
+
+\end{document}
diff --git a/c_embedded/doc/lcd_datasheet.pdf b/c_embedded/doc/lcd_datasheet.pdf
Binary files differ.
diff --git a/c_embedded/doc/pic16f87xa_datasheet.pdf b/c_embedded/doc/pic16f87xa_datasheet.pdf
Binary files differ.
diff --git a/c_embedded/doc/res/schem.png b/c_embedded/doc/res/schem.png
Binary files differ.
diff --git a/c_embedded/doc/res/uniwalogo.png b/c_embedded/doc/res/uniwalogo.png
Binary files differ.
diff --git a/c_embedded/schem/pic.pdf b/c_embedded/schem/pic.pdf
Binary files differ.
diff --git a/c_embedded/schem/pic.pro b/c_embedded/schem/pic.pro
@@ -1,4 +1,4 @@
-update=Tue Jan 25 02:02:50 2022
+update=Mon Jan 31 23:37:10 2022
version=1
last_client=kicad
[general]
@@ -34,7 +34,7 @@ LibDir=
[schematic_editor]
version=1
PageLayoutDescrFile=layout.kicad_wks
-PlotDirectoryName=./
+PlotDirectoryName=../doc/
SubpartIdSeparator=0
SubpartFirstId=65
NetFmtName=
diff --git a/c_embedded/schem/pic.sch b/c_embedded/schem/pic.sch
@@ -276,7 +276,7 @@ L Device:Crystal OSC1
U 1 1 61EB43E4
P 4200 3000
F 0 "OSC1" H 4200 3268 50 0000 C CNN
-F 1 "8MHz" H 4200 3177 50 0000 C CNN
+F 1 "16MHz" H 4200 3177 50 0000 C CNN
F 2 "" H 4200 3000 50 0001 C CNN
F 3 "~" H 4200 3000 50 0001 C CNN
1 4200 3000
@@ -462,4 +462,12 @@ Wire Wire Line
7850 5800 7850 4800
Wire Wire Line
7850 4800 7450 4800
+Entry Bus Bus
+ 2200 2000 2300 2100
+Entry Bus Bus
+ 2200 2000 2300 2100
+Entry Bus Bus
+ 2200 2000 2300 2100
+Entry Bus Bus
+ 2200 2000 2300 2100
$EndSCHEMATC
diff --git a/c_embedded/schem/pic.sch-bak b/c_embedded/schem/pic.sch-bak
@@ -276,7 +276,7 @@ L Device:Crystal OSC1
U 1 1 61EB43E4
P 4200 3000
F 0 "OSC1" H 4200 3268 50 0000 C CNN
-F 1 "8MHz" H 4200 3177 50 0000 C CNN
+F 1 "16MHz" H 4200 3177 50 0000 C CNN
F 2 "" H 4200 3000 50 0001 C CNN
F 3 "~" H 4200 3000 50 0001 C CNN
1 4200 3000
@@ -426,4 +426,40 @@ Wire Wire Line
3800 4800 3800 4400
Wire Wire Line
3800 4400 5650 4400
+Wire Wire Line
+ 5000 4800 5000 4750
+Wire Wire Line
+ 5000 4750 5400 4750
+Wire Wire Line
+ 5400 4750 5400 6000
+Wire Wire Line
+ 5400 6000 8050 6000
+Wire Wire Line
+ 8050 6000 8050 4600
+Wire Wire Line
+ 8050 4600 7450 4600
+Wire Wire Line
+ 4900 4800 4900 4650
+Wire Wire Line
+ 4900 4650 5500 4650
+Wire Wire Line
+ 5500 4650 5500 5900
+Wire Wire Line
+ 5500 5900 7950 5900
+Wire Wire Line
+ 7950 5900 7950 4700
+Wire Wire Line
+ 7950 4700 7450 4700
+Wire Wire Line
+ 4800 4800 4800 4550
+Wire Wire Line
+ 4800 4550 5600 4550
+Wire Wire Line
+ 5600 4550 5600 5800
+Wire Wire Line
+ 5600 5800 7850 5800
+Wire Wire Line
+ 7850 5800 7850 4800
+Wire Wire Line
+ 7850 4800 7450 4800
$EndSCHEMATC
diff --git a/c_embedded/schem/schem.pdf b/c_embedded/schem/schem.pdf
Binary files differ.
diff --git a/c_embedded/src/Makefile b/c_embedded/src/Makefile
@@ -1,7 +1,40 @@
-all:
- sdcc --use-non-free -mpic14 -p16f877a main.c
- pk2cmd -P PIC16F877A -E
- pk2cmd -P PIC16F877A -X -M -F main.hex
+.POSIX:
+
+BIN = prog
+CC = sdcc
+CPPFLAGS =
+CFLAGS = --use-non-free -mpic14 -p16f877a ${CPPFLAGS}
+PIC = PIC16F877A
+
+SRC = main.c \
+ tmr0.c \
+ lcd.c \
+ i2c.c \
+ bme280.c \
+ util.c
+
+OBJ = ${SRC:.c=.o}
+
+all: options ${BIN}
+
+options:
+ @echo ${BIN} build options:
+ @echo "CC = ${CC}"
+ @echo "CFLAGS = ${CFLAGS}"
+
+${BIN}: ${OBJ}
+ ${CC} ${OBJ} ${CFLAGS} -o $@
+
+.c.o:
+ ${CC} -c ${CFLAGS} $<
+
+flash: all
+ pk2cmd -P ${PIC} -X -M -F ${BIN}.hex
+
+erase: all
+ pk2cmd -P ${PIC} -E -F ${BIN}.hex
clean:
- rm -f *.asm *.cod *.hex *.lst *.o
+ rm -f *.hex *.asm *.cod *.hex *.lst *.o *.core
+
+.PHONY: all options clean flash clean
diff --git a/c_embedded/src/bme280.c b/c_embedded/src/bme280.c
@@ -0,0 +1,206 @@
+#include "bme280.h"
+#include "i2c.h"
+#include "tmr0.h"
+
+#define MODE_WRITE 0
+#define MODE_READ 1
+
+#define BME280_DELAY 100
+
+#define BME280_SAMPLE_SKIP 0x00
+#define BME280_SAMPLE_X1 0x01
+#define BME280_FILTER_OFF 0x00
+#define BME280_STANDBY_0_5 0x00
+#define BME280_MODE_NORMAL 0x03
+
+#define BME280_ADDR 0xee
+#define BME280_CHIPID 0x60
+
+#define BME280_REG_DIG_T1 0x88
+#define BME280_REG_DIG_T2 0x8a
+#define BME280_REG_DIG_T3 0x8c
+
+#define BME280_REG_DIG_H1 0xa1
+#define BME280_REG_DIG_H2 0xe1
+#define BME280_REG_DIG_H3 0xe3
+#define BME280_REG_DIG_H4 0xe4
+#define BME280_REG_DIG_H5 0xe5
+#define BME280_REG_DIG_H6 0xe7
+
+#define BME280_REG_CHIPID 0xd0
+#define BME280_REG_SOFTRESET 0xe0
+
+#define BME280_REG_CTLHUM 0xf2
+#define BME280_REG_STATUS 0xf3
+#define BME280_REG_CTL 0xf4
+#define BME280_REG_CONFIG 0xf5
+#define BME280_REG_PRESS_MSB 0xf7
+
+struct bme280_calib {
+ uint16_t dig_t1;
+ int16_t dig_t2;
+ int16_t dig_t3;
+ /* Pressure fields are not used to preserve space. */
+ uint8_t dig_h1;
+ int16_t dig_h2;
+ uint8_t dig_h3;
+ int16_t dig_h4;
+ int16_t dig_h5;
+ int8_t dig_h6;
+};
+
+static void bme280_write(uint8_t, uint8_t);
+static uint8_t bme280_read8(uint8_t);
+static uint16_t bme280_read16(uint8_t);
+static void bme280_update(void);
+
+static struct bme280_calib cal;
+static int32_t adc_t, adc_h, t_fine;
+
+static void
+bme280_write(uint8_t reg, uint8_t dat)
+{
+ i2c_start();
+ i2c_write(BME280_ADDR | MODE_WRITE);
+ i2c_write(reg);
+ i2c_write(dat);
+ i2c_stop();
+}
+
+static uint8_t
+bme280_read8(uint8_t reg)
+{
+ uint8_t c;
+
+ i2c_start();
+ i2c_write(BME280_ADDR | MODE_WRITE);
+ i2c_write(reg);
+ i2c_restart();
+ i2c_write(BME280_ADDR | MODE_READ);
+ c = i2c_read(0);
+ i2c_stop();
+ return (c);
+}
+
+static uint16_t
+bme280_read16(uint8_t reg)
+{
+ uint16_t c;
+
+ i2c_start();
+ i2c_write(BME280_ADDR | MODE_WRITE);
+ i2c_write(reg);
+ i2c_restart();
+ i2c_write(BME280_ADDR | MODE_READ);
+ c = i2c_read(1);
+ c |= i2c_read(0) << 8;
+ i2c_stop();
+ return (c);
+}
+
+static void
+bme280_update(void)
+{
+ union {
+ uint8_t a[4];
+ uint32_t v;
+ } r;
+
+ i2c_start();
+ i2c_write(BME280_ADDR | MODE_WRITE);
+ i2c_write(BME280_REG_PRESS_MSB);
+ i2c_restart();
+ i2c_write(BME280_ADDR | MODE_READ);
+
+ /* Ignore pressure */
+ (void)i2c_read(1);
+ (void)i2c_read(1);
+ (void)i2c_read(1);
+
+ r.a[3] = 0x00;
+ r.a[2] = i2c_read(1);
+ r.a[1] = i2c_read(1);
+ r.a[0] = i2c_read(1);
+ adc_t = (r.v >> 4) & 0xfffff;
+
+ r.a[2] = 0x00;
+ r.a[1] = i2c_read(1);
+ r.a[0] = i2c_read(1);
+ adc_h = (r.v >> 4) & 0xffff;
+
+ i2c_stop();
+}
+
+int
+bme280_init(void)
+{
+ if (bme280_read8(BME280_REG_CHIPID) != BME280_CHIPID)
+ return (-1);
+ bme280_write(BME280_REG_SOFTRESET, 0xb6);
+ tmr0_delay_ms(BME280_DELAY);
+ while ((bme280_read8(BME280_REG_STATUS) & 0x01) == 0x01)
+ tmr0_delay_ms(BME280_DELAY);
+
+ cal.dig_t1 = bme280_read16(BME280_REG_DIG_T1);
+ cal.dig_t2 = bme280_read16(BME280_REG_DIG_T2);
+ cal.dig_t3 = bme280_read16(BME280_REG_DIG_T3);
+
+ cal.dig_h1 = bme280_read8(BME280_REG_DIG_H1);
+ cal.dig_h2 = bme280_read16(BME280_REG_DIG_H2);
+ cal.dig_h3 = bme280_read8(BME280_REG_DIG_H3);
+ cal.dig_h4 = ((uint16_t)bme280_read8(BME280_REG_DIG_H4) << 4) |
+ (bme280_read8(BME280_REG_DIG_H4 + 1) & 0x0f);
+ if (cal.dig_h4 & 0x0800) /* H4 < 0 */
+ cal.dig_h4 |= 0xf000;
+ cal.dig_h5 = ((uint16_t)bme280_read8(BME280_REG_DIG_H5 + 1) << 4) |
+ (bme280_read8(BME280_REG_DIG_H5) >> 4);
+ if (cal.dig_h5 & 0x0800) /* H5 < 0 */
+ cal.dig_h5 |= 0xf000;
+ cal.dig_h6 = bme280_read8(BME280_REG_DIG_H6);
+
+ bme280_write(BME280_REG_CTLHUM, BME280_SAMPLE_X1);
+ bme280_write(BME280_REG_CONFIG, ((BME280_STANDBY_0_5 << 5) |
+ (BME280_FILTER_OFF << 2)) & 0xfc);
+ bme280_write(BME280_REG_CTL, ((BME280_SAMPLE_X1 << 5) |
+ (BME280_SAMPLE_SKIP << 2)) | BME280_MODE_NORMAL);
+
+ return (0);
+}
+
+int32_t
+bme280_read_temp(void)
+{
+ int32_t v1, v2;
+
+ bme280_update();
+ v1 = ((((adc_t / 8) - ((int32_t)cal.dig_t1 * 2))) *
+ ((int32_t)cal.dig_t2)) / 2048;
+ v2 = (((((adc_t / 16) - ((int32_t)cal.dig_t1)) *
+ ((adc_t / 16) - ((int32_t)cal.dig_t1))) / 4096) *
+ ((int32_t)cal.dig_t3)) / 16384;
+
+ t_fine = v1 + v2;
+
+ return ((t_fine * 5 + 128) / 256);
+}
+
+uint32_t
+bme280_read_humid(void)
+{
+ return (0);
+ /*int32_t v;*/
+
+ /*v = (t_fine - ((int32_t)76800));*/
+
+ /*v = (((((adc_h * 16384) - (((int32_t)cal.dig_h4) * 1048576) -*/
+ /*(((int32_t)cal.dig_h5) * v)) + ((int32_t)16384)) / 32768) **/
+ /*(((((((v * ((int32_t)cal.dig_h6)) / 1024) **/
+ /*(((v * ((int32_t)cal.dig_h3)) / 2048) + ((int32_t)32768))) / 1024) +*/
+ /*((int32_t)2097152)) * ((int32_t)cal.dig_h2) + 8192) / 16384));*/
+
+ /*v = (v - (((((v / 32768) * (v / 32768)) / 128) * ((int32_t)cal.dig_h1)) / 16));*/
+ /*v = (v < 0 ? 0 : v);*/
+ /*v = (v > 419430400 ? 419430400 : v);*/
+
+ /*return ((uint32_t)(v / 4096));*/
+}
diff --git a/c_embedded/src/bme280.h b/c_embedded/src/bme280.h
@@ -0,0 +1,10 @@
+#ifndef _BME280_H_
+#define _BME280_H_
+
+#include <stdint.h>
+
+int bme280_init(void);
+int32_t bme280_read_temp(void);
+uint32_t bme280_read_humid(void);
+
+#endif /* _BME280_H_ */
diff --git a/c_embedded/src/extern.h b/c_embedded/src/extern.h
@@ -0,0 +1,25 @@
+#ifndef _EXTERN_H_
+#define _EXTERN_H_
+
+#define NO_BIT_DEFINES
+#include <pic14regs.h>
+#include <stdint.h>
+
+/* MCU related constants */
+#define _XTAL_FREQ 16000000 /* Crystal oscillator running at 16MHz */
+
+#define BTN_PORT PORTBbits.RB0
+#define BTN_TRIS TRISBbits.TRISB0
+#define BTN_DEBOUNCE_TIME_MS 20
+
+#define LED_PORT PORTBbits.RB1
+#define LED_TRIS TRISBbits.TRISB1
+
+#define OUTPUT 0
+#define INPUT 1
+
+/* Non MCU related constants */
+#define NULL ((void *)0)
+#define BUFSIZ (3 * sizeof(uint32_t))
+
+#endif /* _EXTERN_H_ */
diff --git a/c_embedded/src/i2c.c b/c_embedded/src/i2c.c
@@ -0,0 +1,67 @@
+#include "extern.h"
+#include "i2c.h"
+
+#define I2C_SCL TRISCbits.TRISC3
+#define I2C_SDA TRISCbits.TRISC4
+
+void
+i2c_init(uint8_t mode, uint8_t slew, uint32_t freq)
+{
+ I2C_SCL = INPUT;
+ I2C_SDA = INPUT;
+ SSPCON = mode | 0x20; /* MCU as master */
+ SSPCON2 = 0;
+ SSPADD = (_XTAL_FREQ / (4 * freq)) - 1; /* Bus clock speed */
+ SSPSTAT &= 0x3f;
+ SSPSTAT |= slew;
+}
+
+void
+i2c_hold(void)
+{
+ while ((SSPSTATbits.R_W) || (SSPCON2 & 0x1f))
+ ; /* nothing */
+}
+
+void
+i2c_start(void)
+{
+ i2c_hold();
+ SSPCON2bits.SEN = 1;
+}
+
+void
+i2c_stop(void)
+{
+ i2c_hold();
+ SSPCON2bits.PEN = 1;
+}
+
+void
+i2c_restart(void)
+{
+ i2c_hold();
+ SSPCON2bits.RSEN = 1;
+}
+
+void
+i2c_write(uint8_t c)
+{
+ SSPBUF = c;
+ i2c_hold();
+}
+
+uint8_t
+i2c_read(uint8_t ack)
+{
+ uint8_t c;
+
+ SSPCON2bits.RCEN = 1;
+ while (SSPSTATbits.BF == 0)
+ ; /* nothing */
+ c = SSPBUF;
+ i2c_hold();
+ SSPCON2bits.ACKDT = ack ? 0 : 1;
+ SSPCON2bits.ACKEN = 1;
+ return (c);
+}
diff --git a/c_embedded/src/i2c.h b/c_embedded/src/i2c.h
@@ -0,0 +1,18 @@
+#ifndef _I2C_H_
+#define _I2C_H_
+
+#include <stdint.h>
+
+#define I2C_MASTER 0x08
+#define I2C_SLEW_OFF 0x80
+#define I2C_SLEW_ON 0x00
+
+void i2c_init(uint8_t, uint8_t, uint32_t);
+void i2c_hold(void);
+void i2c_start(void);
+void i2c_stop(void);
+void i2c_restart(void);
+void i2c_write(uint8_t);
+uint8_t i2c_read(uint8_t);
+
+#endif /* _I2C_H_ */
diff --git a/c_embedded/src/lcd.c b/c_embedded/src/lcd.c
@@ -0,0 +1,50 @@
+#include "extern.h"
+#include "lcd.h"
+#include "tmr0.h"
+
+#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_RS_TRIS TRISCbits.TRISC0
+#define LCD_RW_TRIS TRISCbits.TRISC1
+#define LCD_EN_TRIS TRISCbits.TRISC2
+#define LCD_PORT_DATA PORTD
+#define LCD_TRIS_DATA TRISD
+
+void
+lcd_init(void)
+{
+ LCD_RS_TRIS = OUTPUT;
+ LCD_RW_TRIS = OUTPUT;
+ LCD_EN_TRIS = OUTPUT;
+ LCD_PORT_DATA = OUTPUT;
+ LCD_TRIS_DATA = OUTPUT;
+ LCD_RS = 0;
+ LCD_RW = 0;
+ LCD_EN = 0;
+
+ lcd_cmd(LCD_MODE);
+ tmr0_delay_ms(LCD_DELAY_STARTUP);
+ lcd_cmd(LCD_CURS_ROW1);
+ lcd_cmd(LCD_CURS_OFF);
+ lcd_cmd(LCD_CURS_INC);
+ lcd_cmd(LCD_CLEAR);
+}
+
+void
+lcd_data(uint8_t c, uint8_t rs)
+{
+ LCD_RS = rs;
+ LCD_RW = 0;
+ LCD_PORT_DATA = c;
+ LCD_EN = 1;
+ tmr0_delay_ms(LCD_DELAY_CMD);
+ LCD_EN = 0;
+}
+
+void
+lcd_puts(const char *str)
+{
+ while (*str != '\0')
+ lcd_putc(*str++);
+}
diff --git a/c_embedded/src/lcd.h b/c_embedded/src/lcd.h
@@ -0,0 +1,26 @@
+#ifndef _LCD_H_
+#define _LCD_H_
+
+#include <stdint.h>
+
+#define LCD_DELAY_STARTUP 15
+#define LCD_DELAY_CMD 2
+#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_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 /* 8-bit, 16x2 */
+//TODO: backlight
+
+/* Function macros */
+#define lcd_putc(c) lcd_data(c, LCD_SEL_DATA)
+#define lcd_cmd(cmd) lcd_data(cmd, LCD_SEL_INST)
+
+void lcd_init(void);
+void lcd_data(uint8_t, uint8_t);
+void lcd_puts(const char *);
+
+#endif /* _LCD_H_ */
diff --git a/c_embedded/src/main.c b/c_embedded/src/main.c
@@ -1,161 +1,71 @@
-#define NO_BIT_DEFINES
-#include <pic14regs.h>
-#include <stdint.h>
-/*#include <string.h>*/
+#include "extern.h"
+#include "bme280.h"
+#include "i2c.h"
+#include "lcd.h"
+#include "tmr0.h"
+#include "util.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 TMR0_CLK0 (0 << 5) /* Use the CLK0 pin */
-/*
- * 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 TMR0_PRESCALAR_256 0b0111
-/*
- * 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)) = ~240
- *
- * sdcc thinks there's an overflow here (hint: he's wrong)...
- */
-#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
-#define BTN_DEBOUNCE_TIME_MS 20
-
-#define LED_PORT PORTBbits.RB1
-#define LED_TRIS TRISBbits.TRISB1
-
-#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_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_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 /* 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)
-
-typedef void (*ev_handler)(void);
-
-struct timer_req {
- ev_handler handler; /* ISR callback */
- uint32_t rate; /* Interval */
- uint32_t cnt; /* Current time */
-};
-
-/* 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);
-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 void print_tp(int32_t);
+static void led_blink(void);
-/* Global variables */
-static struct timer_req reqs[TMR0_REQ_MAX];
+static void button_debounce(void);
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 uint32_t humid; /* Current humidity */
+static int32_t tp; /* Current temperature */
+static int32_t maxtp = -100; /* Max temperature */
static char buf[BUFSIZ+1] = {0}; /* Generic buffer */
-/* Function implementations */
-static void
-tmr0_init(void)
-{
- memset(reqs, 0, sizeof(reqs));
- OPTION_REG = 0;
- 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 */
-}
+#define LCD_PUTS_INT(buf, v) do { \
+ memset(buf, 0, sizeof(buf)); \
+ lcd_puts(itoa(&buf[sizeof(buf)-1], v)); \
+} while (0)
static void
-tmr0_delay_ms(uint32_t t)
+ctx_main(void)
{
- while (t--) {
- while (INTCONbits.TMR0IF == 0)
- ; /* nothing */
- INTCONbits.TMR0IF = 0;
- TMR0 = TMR0_DELAY;
- }
+ lcd_cmd(LCD_CURS_ROW1);
+ lcd_puts("19390133");
+
+ lcd_cmd(LCD_CURS_ROW2);
+ print_tp(tp);
+
+ LCD_PUTS_INT(buf, humid / 1024);
+ lcd_putc('.');
+ LCD_PUTS_INT(buf, ((humid * 100) / 1024) % 100);
+ lcd_putc('%');
}
-static int
-tmr0_set_event(ev_handler handler, uint32_t rate)
+static void
+ctx_uptime_maxtp(void)
{
- struct timer_req *r;
- uint8_t i;
+ lcd_cmd(LCD_CURS_ROW1);
+ lcd_puts("T: ");
+ LCD_PUTS_INT(buf, timecnt);
- for (i = 0; i < TMR0_REQ_MAX; i++) {
- r = &reqs[i];
- if (r->handler != NULL)
- continue;
- r->handler = handler;
- r->rate = rate;
- r->cnt = 0;
- return (1);
- }
- return (0);
+ lcd_cmd(LCD_CURS_ROW2);
+ lcd_puts("Max: ");
+ print_tp(maxtp);
}
static void
-tmr0_isr(void) __interrupt
+print_tp(int32_t tp)
{
- struct timer_req *r;
- uint8_t i;
-
- if (INTCONbits.TMR0IF != 1)
- return;
- for (i = 0; i < TMR0_REQ_MAX; i++) {
- r = &reqs[i];
- if (r->handler == NULL)
- continue;
- if (++r->cnt == r->rate) {
- r->handler();
- r->cnt = 0;
- }
- }
- TMR0 = TMR0_DELAY;
- INTCONbits.TMR0IF = 0; /* Clear interrupt flags */
+ /* TODO: handle negative */
+ LCD_PUTS_INT(buf, tp / 100);
+ lcd_putc('.');
+ LCD_PUTS_INT(buf, tp % 100);
+ lcd_puts("\337C ");
}
+#undef LCD_PUTS_INT
+
static void
led_blink(void)
{
@@ -181,107 +91,11 @@ button_debounce(void)
}
cnt = BTN_DEBOUNCE_TIME_MS;
} else if (cnt != 0) {
- cnt--;
f_ctx = 0;
+ cnt--;
}
}
-static void
-lcd_init(void)
-{
- LCD_PORT_CTL_DIR = OUTPUT;
- LCD_PORT_DATA_DIR = OUTPUT;
- LCD_RS = 0;
- LCD_RW = 0;
- LCD_EN = 0;
-
- 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_CLEAR);
-}
-
-static void
-lcd_data(uint8_t c, uint8_t rs)
-{
- LCD_RS = rs;
- LCD_RW = 0;
- LCD_PORT_DATA = c;
- LCD_EN = 1;
- tmr0_delay_ms(2);
- LCD_EN = 0;
-}
-
-static void
-lcd_puts(const char *str)
-{
- while (*str != '\0')
- 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)
{
@@ -289,12 +103,20 @@ main(void)
tmr0_set_event(&led_blink, 1000);
tmr0_set_event(&button_debounce, 1);
lcd_init();
+ i2c_init(I2C_MASTER, I2C_SLEW_OFF, 1000000);
+ if (bme280_init() < 0) {
+ lcd_puts("BME280 error");
+ for (;;); /* Hang */
+ }
BTN_TRIS = INPUT;
- LED_PORT = 0; /* LED on */
+ LED_PORT = 1; /* LED on */
LED_TRIS = OUTPUT;
for (;;) {
+ if ((tp = bme280_read_temp()) > maxtp)
+ maxtp = tp;
+ humid = bme280_read_humid();
lcd_cmd(LCD_CLEAR);
if (!f_ctx)
ctx_main();
diff --git a/c_embedded/src/tmr0.c b/c_embedded/src/tmr0.c
@@ -0,0 +1,76 @@
+#include "tmr0.h"
+#include "util.h"
+
+#define TMR0_REQ_MAX 2
+
+struct timer_req {
+ ev_handler handler; /* ISR callback */
+ uint32_t rate; /* Interval */
+ uint32_t cnt; /* Current time */
+};
+
+static void tmr0_isr(void) __interrupt;
+
+static struct timer_req reqs[TMR0_REQ_MAX];
+
+static void
+tmr0_isr(void) __interrupt
+{
+ struct timer_req *r;
+ uint8_t i;
+
+ if (INTCONbits.TMR0IF != 1)
+ return;
+ for (i = 0; i < TMR0_REQ_MAX; i++) {
+ r = &reqs[i];
+ if (r->handler == NULL)
+ continue;
+ if (++r->cnt == r->rate) {
+ r->handler();
+ r->cnt = 0;
+ }
+ }
+ TMR0 = TMR0_DELAY;
+ INTCONbits.TMR0IF = 0; /* Clear interrupt flags */
+}
+
+void
+tmr0_init(void)
+{
+ memset(reqs, 0, sizeof(reqs));
+ OPTION_REG = 0;
+ 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 */
+}
+
+void
+tmr0_delay_ms(uint32_t t)
+{
+ while (t--) {
+ while (INTCONbits.TMR0IF == 0)
+ ; /* nothing */
+ INTCONbits.TMR0IF = 0;
+ TMR0 = TMR0_DELAY;
+ }
+}
+
+int
+tmr0_set_event(ev_handler handler, uint32_t rate)
+{
+ struct timer_req *r;
+ uint8_t i;
+
+ for (i = 0; i < TMR0_REQ_MAX; i++) {
+ r = &reqs[i];
+ if (r->handler != NULL)
+ continue;
+ r->handler = handler;
+ r->rate = rate;
+ r->cnt = 0;
+ return (1);
+ }
+ return (0);
+}
diff --git a/c_embedded/src/tmr0.h b/c_embedded/src/tmr0.h
@@ -0,0 +1,30 @@
+#ifndef _TMR0_H_
+#define _TMR0_H_
+
+#include "extern.h"
+
+#define TMR0_CLK0 (0 << 5) /* Use the CLK0 pin */
+/*
+ * 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 TMR0_PRESCALAR_256 0b0111
+/*
+ * 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)) = ~240
+ *
+ * sdcc thinks there's an overflow here (hint: he's wrong)...
+ */
+#define TMR0_DELAY (256 - ((1 * (_XTAL_FREQ / 1000)) / (256 * 4)))
+
+typedef void (*ev_handler)(void);
+
+void tmr0_init(void);
+void tmr0_delay_ms(uint32_t);
+int tmr0_set_event(ev_handler, uint32_t);
+
+#endif /* _TMR0_H_ */
diff --git a/c_embedded/src/util.c b/c_embedded/src/util.c
@@ -0,0 +1,27 @@
+#include "util.h"
+
+/*
+ * To avoid reversing the string, the caller has to provide a pointer to the
+ * end of the string.
+ */
+char *
+itoa(char *s, int n)
+{
+ *s = '\0';
+ if (n == 0)
+ *--s = '0';
+ for (; n; n /= 10)
+ *--s = n % 10 + '0';
+ return (s);
+}
+
+void *
+memset(void *dst, int v, int len)
+{
+ unsigned char *dst0;
+
+ dst0 = dst;
+ while (len--)
+ *dst0++ = v;
+ return (dst);
+}
diff --git a/c_embedded/src/util.h b/c_embedded/src/util.h
@@ -0,0 +1,7 @@
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
+char *itoa(char *, int);
+void *memset(void *, int, int);
+
+#endif /* _UTIL_H_ */