uni

University stuff
git clone git://git.margiolis.net/uni.git
Log | Files | Refs | README | LICENSE

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:
Ac_embedded/doc/bme280_datasheet.pdf | 0
Ac_embedded/doc/doc.pdf | 0
Ac_embedded/doc/doc.tex | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ac_embedded/doc/lcd_datasheet.pdf | 0
Ac_embedded/doc/pic16f87xa_datasheet.pdf | 0
Ac_embedded/doc/res/schem.png | 0
Ac_embedded/doc/res/uniwalogo.png | 0
Ac_embedded/schem/pic.pdf | 0
Mc_embedded/schem/pic.pro | 4++--
Mc_embedded/schem/pic.sch | 10+++++++++-
Mc_embedded/schem/pic.sch-bak | 38+++++++++++++++++++++++++++++++++++++-
Dc_embedded/schem/schem.pdf | 0
Mc_embedded/src/Makefile | 43++++++++++++++++++++++++++++++++++++++-----
Ac_embedded/src/bme280.c | 206+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ac_embedded/src/bme280.h | 10++++++++++
Ac_embedded/src/extern.h | 25+++++++++++++++++++++++++
Ac_embedded/src/i2c.c | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ac_embedded/src/i2c.h | 18++++++++++++++++++
Ac_embedded/src/lcd.c | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Ac_embedded/src/lcd.h | 26++++++++++++++++++++++++++
Mc_embedded/src/main.c | 284+++++++++++++++----------------------------------------------------------------
Ac_embedded/src/tmr0.c | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ac_embedded/src/tmr0.h | 30++++++++++++++++++++++++++++++
Ac_embedded/src/util.c | 27+++++++++++++++++++++++++++
Ac_embedded/src/util.h | 7+++++++
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_ */