divided some files into h and c, removed temporary "projects"
This commit is contained in:
@@ -6,3 +6,5 @@ This is my ever-evolving library (not only) for AVR programming.
|
||||
When I'm done with a project, I copy the current library to the project, so it doesn't break when I do further improvements.
|
||||
|
||||
Each library file contains a large comment block explaining it's function.
|
||||
|
||||
You may need to add "c" files to your makefile for some of the library files.
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#include <avr/io.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "calc.h"
|
||||
#include "adc.h"
|
||||
|
||||
/** Initialize the ADC */
|
||||
void adc_init()
|
||||
{
|
||||
ADCSRA |= _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // 128 prescaler -> 125 kHz
|
||||
ADMUX |= _BV(REFS0); // Voltage reference
|
||||
sbi(ADCSRA, ADEN); // Enable ADC
|
||||
}
|
||||
|
||||
|
||||
/** Disable AD */
|
||||
void adc_disable()
|
||||
{
|
||||
cbi(ADCSRA, ADEN);
|
||||
}
|
||||
|
||||
|
||||
/** Sample analog pin with 8-bit precision */
|
||||
uint8_t adc_read_byte(uint8_t channel)
|
||||
{
|
||||
write_low_nibble(ADMUX, channel); // Select channel to sample
|
||||
sbi(ADMUX, ADLAR); // Align result to left
|
||||
sbi(ADCSRA, ADSC); // Start conversion
|
||||
|
||||
while(bit_is_high(ADCSRA, ADSC)); // Wait for it...
|
||||
|
||||
return ADCH; // The upper 8 bits of ADC result
|
||||
}
|
||||
|
||||
|
||||
/** Sample analog pin with 10-bit precision */
|
||||
uint16_t adc_read_word(uint8_t channel)
|
||||
{
|
||||
write_low_nibble(ADMUX, channel); // Select channel to sample
|
||||
cbi(ADMUX, ADLAR); // Align result to right
|
||||
sbi(ADCSRA, ADSC); // Start conversion
|
||||
|
||||
while(get_bit(ADCSRA, ADSC)); // Wait for it...
|
||||
|
||||
return ADCW; // The whole ADC word (10 bits)
|
||||
}
|
||||
+9
-29
@@ -1,39 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Utilities for build-in A/D converter
|
||||
*/
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <stdbool.h>
|
||||
#include "calc.h"
|
||||
|
||||
/** Initialize the ADC */
|
||||
void adc_init()
|
||||
{
|
||||
ADCSRA |= _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // 128 prescaler -> 125 kHz
|
||||
ADMUX |= _BV(REFS0); // Voltage reference
|
||||
sbi(ADCSRA, ADEN); // Enable ADC
|
||||
}
|
||||
void adc_init();
|
||||
|
||||
/** Disable AD (for power saving?) */
|
||||
void adc_disable();
|
||||
|
||||
/** Sample analog pin with 8-bit precision */
|
||||
uint8_t adc_read_byte(uint8_t channel)
|
||||
{
|
||||
write_low_nibble(ADMUX, channel); // Select channel to sample
|
||||
sbi(ADMUX, ADLAR); // Align result to left
|
||||
sbi(ADCSRA, ADSC); // Start conversion
|
||||
|
||||
while(bit_is_high(ADCSRA, ADSC)); // Wait for it...
|
||||
|
||||
return ADCH; // The upper 8 bits of ADC result
|
||||
}
|
||||
|
||||
uint8_t adc_read_byte(uint8_t channel);
|
||||
|
||||
/** Sample analog pin with 10-bit precision */
|
||||
uint16_t adc_read_word(uint8_t channel)
|
||||
{
|
||||
write_low_nibble(ADMUX, channel); // Select channel to sample
|
||||
cbi(ADMUX, ADLAR); // Align result to right
|
||||
sbi(ADCSRA, ADSC); // Start conversion
|
||||
|
||||
while(get_bit(ADCSRA, ADSC)); // Wait for it...
|
||||
|
||||
return ADCW; // The whole ADC word (10 bits)
|
||||
}
|
||||
uint16_t adc_read_word(uint8_t channel);
|
||||
|
||||
+2
-1
@@ -11,6 +11,7 @@
|
||||
XX_r (_g, _b) ... extract component from the color, and convert it to 0..255
|
||||
*/
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
@@ -79,5 +80,5 @@ typedef uint8_t rgb6_t;
|
||||
#define rgb6_rgb24(c) rgb24(rgb6_r(c), rgb6_g(c), rgb6_b(c))
|
||||
#define rgb6_rgb24c(c) rgb24c(rgb6_r(c), rgb6_g(c), rgb6_b(c))
|
||||
|
||||
|
||||
#define add_xrgb(x, y) ((xrgb_t) { (((y).r > (255 - (x).r)) ? 255 : ((x).r + (y).r)), (((y).g > (255 - (x).g)) ? 255 : ((x).g + (y).g)), (((y).b > 255 - (x).b) ? 255 : ((x).b + (y).b)) })
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#include <avr/io.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "debounce.h"
|
||||
#include "calc.h"
|
||||
#include "pins.h"
|
||||
#include "debo_config.h"
|
||||
|
||||
/** Debounce data array */
|
||||
uint8_t debo_next_slot = 0;
|
||||
|
||||
uint8_t debo_register(PORT_P reg, uint8_t bit, bool invert)
|
||||
{
|
||||
debo_slots[debo_next_slot] = (debo_slot_t){
|
||||
.reg = reg,
|
||||
.bit = bit | ((invert & 1) << 7) | (get_bit_p(reg, bit) << 6), // bit 7 = invert, bit 6 = state
|
||||
.count = 0,
|
||||
};
|
||||
|
||||
return debo_next_slot++;
|
||||
}
|
||||
|
||||
|
||||
/** Check debounced pins, should be called periodically. */
|
||||
void debo_tick()
|
||||
{
|
||||
for (uint8_t i = 0; i < debo_next_slot; i++) {
|
||||
// current pin value (right 3 bits, xored with inverse bit)
|
||||
bool value = get_bit_p(debo_slots[i].reg, debo_slots[i].bit & 0x7);
|
||||
|
||||
if (value != get_bit(debo_slots[i].bit, 6)) {
|
||||
|
||||
// different pin state than last recorded state
|
||||
if (debo_slots[i].count < DEBO_TICKS) {
|
||||
debo_slots[i].count++;
|
||||
} else {
|
||||
// overflown -> latch value
|
||||
set_bit(debo_slots[i].bit, 6, value); // set state bit
|
||||
debo_slots[i].count = 0;
|
||||
}
|
||||
} else {
|
||||
debo_slots[i].count = 0; // reset the counter
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
-61
@@ -3,30 +3,34 @@
|
||||
/**
|
||||
An implementation of button debouncer.
|
||||
|
||||
First, the system must be initialized - even before including:
|
||||
----
|
||||
|
||||
#define DEBO_CHANNELS 2
|
||||
#define DEBO_TICKS 5
|
||||
You must provide a config file debo_config.h (next to your main.c)
|
||||
|
||||
#inclue "lib/debounce.h"
|
||||
Example:
|
||||
#pragma once
|
||||
#define DEBO_CHANNELS 2
|
||||
#define DDEBO_TICKS 5
|
||||
|
||||
----
|
||||
|
||||
A pin is registered like this:
|
||||
|
||||
#define BTN1 B,0
|
||||
#define BTN2 B,1
|
||||
#define BTN1 B,0
|
||||
#define BTN2 B,1
|
||||
|
||||
debo_add(BTN0); // The function returns number assigned to the pin (0, 1, ...)
|
||||
debo_add_rev(BTN1); // active low
|
||||
debo_register(&PINB, PB2, 0); // direct access - register, pin & invert
|
||||
debo_add(BTN0); // The function returns number assigned to the pin (0, 1, ...)
|
||||
debo_add_rev(BTN1); // active low
|
||||
debo_register(&PINB, PB2, 0); // direct access - register, pin & invert
|
||||
|
||||
Then periodically call the tick function (perhaps in a timer interrupt):
|
||||
|
||||
debo_tick();
|
||||
debo_tick();
|
||||
|
||||
To check if input is active, use
|
||||
|
||||
debo_get_pin(0); // state of input registered as #0
|
||||
debo_get_pin(1); // state of input registered as #1
|
||||
debo_get_pin(0); // state of input #0 (registered first)
|
||||
debo_get_pin(1); // state of input #1 (registered second)
|
||||
*/
|
||||
|
||||
#include <avr/io.h>
|
||||
@@ -34,18 +38,7 @@
|
||||
|
||||
#include "calc.h"
|
||||
#include "pins.h"
|
||||
|
||||
|
||||
// Number of pins to debounce
|
||||
#ifndef DEBO_CHANNELS
|
||||
# error "DEBO_CHANNELS not defined!"
|
||||
#endif
|
||||
|
||||
#ifndef DEBO_TICKS
|
||||
# warning "DEBO_TICKS not defined, defaulting to 5!"
|
||||
# define DEBO_TICKS 5
|
||||
#endif
|
||||
|
||||
#include "debo_config.h"
|
||||
|
||||
/* Internal deboucer entry */
|
||||
typedef struct {
|
||||
@@ -54,50 +47,17 @@ typedef struct {
|
||||
uint8_t count; // number of ticks this was in the new state
|
||||
} debo_slot_t;
|
||||
|
||||
/** Debounce data array */
|
||||
debo_slot_t debo_slots[DEBO_CHANNELS];
|
||||
uint8_t debo_next_slot = 0;
|
||||
|
||||
/** Define a debounced pin (must be IO!) */
|
||||
|
||||
/** Add a pin for debouncing */
|
||||
#define debo_add_rev(io) debo_register(&io2pin(io_pack(io)), io2n(io_pack(io)), 1)
|
||||
#define debo_add(io) debo_register(&io2pin(io_pack(io)), io2n(io_pack(io)), 0)
|
||||
|
||||
uint8_t debo_register(PORT_P reg, uint8_t bit, bool invert)
|
||||
{
|
||||
debo_slots[debo_next_slot] = (debo_slot_t){
|
||||
.reg = reg,
|
||||
.bit = bit | ((invert & 1) << 7) | (get_bit_p(reg, bit) << 6), // bit 7 = invert, bit 6 = state
|
||||
.count = 0,
|
||||
};
|
||||
|
||||
return debo_next_slot++;
|
||||
}
|
||||
|
||||
/** Add a pin for debouncing (low level function) */
|
||||
uint8_t debo_register(PORT_P pin_reg_pointer, uint8_t bit, bool invert);
|
||||
|
||||
/** Check debounced pins, should be called periodically. */
|
||||
void debo_tick()
|
||||
{
|
||||
for (uint8_t i = 0; i < debo_next_slot; i++) {
|
||||
// current pin value (right 3 bits, xored with inverse bit)
|
||||
bool value = get_bit_p(debo_slots[i].reg, debo_slots[i].bit & 0x7);
|
||||
|
||||
if (value != get_bit(debo_slots[i].bit, 6)) {
|
||||
|
||||
// different pin state than last recorded state
|
||||
if (debo_slots[i].count < DEBO_TICKS) {
|
||||
debo_slots[i].count++;
|
||||
} else {
|
||||
// overflown -> latch value
|
||||
set_bit(debo_slots[i].bit, 6, value); // set state bit
|
||||
debo_slots[i].count = 0;
|
||||
}
|
||||
} else {
|
||||
debo_slots[i].count = 0; // reset the counter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void debo_tick();
|
||||
|
||||
/** Get a value of debounced pin */
|
||||
#define debo_get_pin(i) (get_bit(debo_slots[i].bit, 6) ^ get_bit(debo_slots[i].bit, 7))
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "colors.h"
|
||||
#include "hsl.h"
|
||||
|
||||
// based on: https://github.com/lewisd32/avr-hsl2rgb
|
||||
xrgb_t hsl2xrgb(const hsl_t cc)
|
||||
{
|
||||
// 0 .. 256*3
|
||||
const uint16_t hh = (uint16_t) cc.h * 3;
|
||||
const uint8_t hue_mod = hh % 256;
|
||||
|
||||
uint8_t r_temp, g_temp, b_temp;
|
||||
if (hh < 256) {
|
||||
r_temp = hue_mod ^ 255;
|
||||
g_temp = hue_mod;
|
||||
b_temp = 0;
|
||||
} else if (hh < 512) {
|
||||
r_temp = 0;
|
||||
g_temp = hue_mod ^ 255;
|
||||
b_temp = hue_mod;
|
||||
} else if (hh < 768) {
|
||||
r_temp = hue_mod;
|
||||
g_temp = 0;
|
||||
b_temp = hue_mod ^ 255;
|
||||
} else {
|
||||
r_temp = 0;
|
||||
g_temp = 0;
|
||||
b_temp = 0;
|
||||
}
|
||||
|
||||
const uint8_t inverse_sat = (cc.s ^ 255);
|
||||
|
||||
xrgb_t rgb;
|
||||
|
||||
uint8_t t8;
|
||||
uint16_t t16;
|
||||
|
||||
#ifdef HSL_LINEAR
|
||||
const uint8_t bri = FADE_128[cc.l>>1];
|
||||
#else
|
||||
const uint8_t bri = cc.l;
|
||||
#endif
|
||||
|
||||
t8 = r_temp;
|
||||
t16 = t8 * cc.s + t8;
|
||||
t16 = t16 + t8;
|
||||
t8 = t16 >> 8;
|
||||
t8 = t8 + inverse_sat;
|
||||
t16 = t8 * bri;
|
||||
t16 = t16 + t8;
|
||||
t8 = t16 >> 8;
|
||||
rgb.r = t8;
|
||||
|
||||
t8 = g_temp;
|
||||
t16 = t8 * cc.s;
|
||||
t16 = t16 + t8;
|
||||
t8 = t16 >> 8;
|
||||
t8 = t8 + inverse_sat;
|
||||
t16 = t8 * bri;
|
||||
t16 = t16 + t8;
|
||||
t8 = t16 >> 8;
|
||||
rgb.g = t8;
|
||||
|
||||
t8 = b_temp;
|
||||
t16 = t8 * cc.s;
|
||||
t16 = t16 + t8;
|
||||
t8 = t16 >> 8;
|
||||
t8 = t8 + inverse_sat;
|
||||
t16 = t8 * bri;
|
||||
t16 = t16 + t8;
|
||||
t8 = t16 >> 8;
|
||||
rgb.b = t8;
|
||||
|
||||
return rgb;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
HSL support (addition to colors.h)
|
||||
*/
|
||||
|
||||
#include "colors.h"
|
||||
|
||||
// Define HSL_LINEAR to get more linear brightness in hsl->rgb conversion
|
||||
#ifdef HSL_LINEAR
|
||||
# include "linear_fade.h"
|
||||
#endif
|
||||
|
||||
// HSL data structure
|
||||
typedef struct {
|
||||
uint8_t h;
|
||||
uint8_t s;
|
||||
uint8_t l;
|
||||
} hsl_t;
|
||||
|
||||
/* Convert HSL to XRGB */
|
||||
xrgb_t hsl2xrgb(const hsl_t color);
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
#include "calc.h"
|
||||
#include "pins.h"
|
||||
#include "nsdelay.h"
|
||||
#include "lcd.h"
|
||||
#include "lcd_config.h"
|
||||
|
||||
// Start address of rows
|
||||
const uint8_t LCD_ROW_ADDR[] = {0x00, 0x40, 0x14, 0x54};
|
||||
|
||||
// Internal prototypes
|
||||
void _lcd_mode_r();
|
||||
void _lcd_mode_w();
|
||||
void _lcd_clk();
|
||||
void _lcd_wait_bf();
|
||||
void _lcd_write_byte(uint8_t bb);
|
||||
uint8_t _lcd_read_byte();
|
||||
|
||||
|
||||
// Write utilities
|
||||
#define _lcd_write_low(bb) _lcd_write_nibble((bb) & 0x0F)
|
||||
#define _lcd_write_high(bb) _lcd_write_nibble(((bb) & 0xF0) >> 4)
|
||||
#define _lcd_write_nibble(nib) do { \
|
||||
write_pin(LCD_D7, get_bit((nib), 3)); \
|
||||
write_pin(LCD_D6, get_bit((nib), 2)); \
|
||||
write_pin(LCD_D5, get_bit((nib), 1)); \
|
||||
write_pin(LCD_D4, get_bit((nib), 0)); \
|
||||
} while(0)
|
||||
|
||||
|
||||
// 0 W, 1 R
|
||||
bool _lcd_mode;
|
||||
|
||||
|
||||
/** Initialize the display */
|
||||
void lcd_init()
|
||||
{
|
||||
// configure pins as output
|
||||
as_output(LCD_E);
|
||||
as_output(LCD_RW);
|
||||
as_output(LCD_RS);
|
||||
_lcd_mode = 1; // force data pins to output
|
||||
_lcd_mode_w();
|
||||
|
||||
// Magic sequence to invoke Cthulhu (or enter 4-bit mode)
|
||||
_delay_ms(16);
|
||||
_lcd_write_nibble(0b0011);
|
||||
_lcd_clk();
|
||||
_delay_ms(5);
|
||||
_lcd_clk();
|
||||
_delay_ms(5);
|
||||
_lcd_clk();
|
||||
_delay_ms(5);
|
||||
_lcd_write_nibble(0b0010);
|
||||
_lcd_clk();
|
||||
_delay_us(100);
|
||||
|
||||
// Configure the display
|
||||
lcd_write_command(LCD_IFACE_4BIT_2LINE);
|
||||
lcd_write_command(LCD_DISABLE);
|
||||
lcd_write_command(LCD_CLEAR);
|
||||
lcd_write_command(LCD_MODE_INC);
|
||||
|
||||
// mark as enabled
|
||||
lcd_enable();
|
||||
}
|
||||
|
||||
|
||||
/** Send a pulse on the ENABLE line */
|
||||
void _lcd_clk()
|
||||
{
|
||||
pin_up(LCD_E);
|
||||
delay_ns(420);
|
||||
pin_down(LCD_E);
|
||||
}
|
||||
|
||||
|
||||
/** Enter READ mode */
|
||||
void _lcd_mode_r()
|
||||
{
|
||||
if (_lcd_mode == 1) return; // already in R mode
|
||||
|
||||
pin_up(LCD_RW);
|
||||
|
||||
as_input_pu(LCD_D7);
|
||||
as_input_pu(LCD_D6);
|
||||
as_input_pu(LCD_D5);
|
||||
as_input_pu(LCD_D4);
|
||||
|
||||
_lcd_mode = 1;
|
||||
}
|
||||
|
||||
|
||||
/** Enter WRITE mode */
|
||||
void _lcd_mode_w()
|
||||
{
|
||||
if (_lcd_mode == 0) return; // already in W mode
|
||||
|
||||
pin_down(LCD_RW);
|
||||
|
||||
as_output(LCD_D7);
|
||||
as_output(LCD_D6);
|
||||
as_output(LCD_D5);
|
||||
as_output(LCD_D4);
|
||||
|
||||
_lcd_mode = 0;
|
||||
}
|
||||
|
||||
|
||||
/** Read a byte */
|
||||
uint8_t _lcd_read_byte()
|
||||
{
|
||||
_lcd_mode_r();
|
||||
|
||||
uint8_t res = 0;
|
||||
|
||||
_lcd_clk();
|
||||
res = (read_pin(LCD_D7) << 7) | (read_pin(LCD_D6) << 6) | (read_pin(LCD_D5) << 5) | (read_pin(LCD_D4) << 4);
|
||||
|
||||
_lcd_clk();
|
||||
res |= (read_pin(LCD_D7) << 3) | (read_pin(LCD_D6) << 2) | (read_pin(LCD_D5) << 1) | (read_pin(LCD_D4) << 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/** Write an instruction byte */
|
||||
void lcd_write_command(uint8_t bb)
|
||||
{
|
||||
_lcd_wait_bf();
|
||||
pin_down(LCD_RS); // select instruction register
|
||||
_lcd_write_byte(bb); // send instruction byte
|
||||
}
|
||||
|
||||
|
||||
/** Write a data byte */
|
||||
void lcd_write_data(uint8_t bb)
|
||||
{
|
||||
_lcd_wait_bf();
|
||||
pin_up(LCD_RS); // select data register
|
||||
_lcd_write_byte(bb); // send data byte
|
||||
}
|
||||
|
||||
|
||||
/** Read BF & Address */
|
||||
uint8_t lcd_read_bf_addr()
|
||||
{
|
||||
pin_down(LCD_RS);
|
||||
return _lcd_read_byte();
|
||||
}
|
||||
|
||||
|
||||
/** Read CGRAM or DDRAM */
|
||||
uint8_t lcd_read_ram()
|
||||
{
|
||||
pin_up(LCD_RS);
|
||||
return _lcd_read_byte();
|
||||
}
|
||||
|
||||
|
||||
/** Write a byte using the 8-bit interface */
|
||||
void _lcd_write_byte(uint8_t bb)
|
||||
{
|
||||
_lcd_mode_w(); // enter W mode
|
||||
|
||||
_lcd_write_high(bb);
|
||||
_lcd_clk();
|
||||
|
||||
_lcd_write_low(bb);
|
||||
_lcd_clk();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Wait until the device is ready */
|
||||
void _lcd_wait_bf()
|
||||
{
|
||||
uint8_t d = 0;
|
||||
while(d++ < 120 && lcd_read_bf_addr() & _BV(7))
|
||||
_delay_us(1);
|
||||
}
|
||||
|
||||
|
||||
/** Send a string to LCD */
|
||||
void lcd_str(char* str_p)
|
||||
{
|
||||
while (*str_p)
|
||||
lcd_char(*str_p++);
|
||||
}
|
||||
|
||||
|
||||
/** Sedn a char to LCD */
|
||||
void lcd_char(const char c)
|
||||
{
|
||||
lcd_write_data(c);
|
||||
}
|
||||
|
||||
|
||||
/** Set cursor position */
|
||||
void lcd_xy(const uint8_t x, const uint8_t y)
|
||||
{
|
||||
lcd_set_addr(LCD_ROW_ADDR[y] + (x));
|
||||
}
|
||||
|
||||
|
||||
uint8_t _lcd_old_cursor = CURSOR_NONE;
|
||||
bool _lcd_enabled = false;
|
||||
|
||||
/** Set LCD cursor. If not enabled, only remember it. */
|
||||
void lcd_cursor(uint8_t type)
|
||||
{
|
||||
_lcd_old_cursor = (type & CURSOR_BOTH);
|
||||
|
||||
if (_lcd_enabled) lcd_write_command(LCD_CURSOR_NONE | _lcd_old_cursor);
|
||||
}
|
||||
|
||||
|
||||
/** Display display (preserving cursor) */
|
||||
void lcd_disable()
|
||||
{
|
||||
lcd_write_command(LCD_DISABLE);
|
||||
_lcd_enabled = false;
|
||||
}
|
||||
|
||||
|
||||
/** Enable display (restoring cursor) */
|
||||
void lcd_enable()
|
||||
{
|
||||
_lcd_enabled = true;
|
||||
lcd_cursor(_lcd_old_cursor);
|
||||
}
|
||||
|
||||
|
||||
/** Go home */
|
||||
void lcd_home()
|
||||
{
|
||||
lcd_write_command(LCD_HOME);
|
||||
}
|
||||
|
||||
|
||||
/** Clear the screen */
|
||||
void lcd_clear()
|
||||
{
|
||||
lcd_write_command(LCD_CLEAR);
|
||||
}
|
||||
|
||||
|
||||
/** Define a glyph */
|
||||
void lcd_define_glyph(const uint8_t index, const uint8_t* array)
|
||||
{
|
||||
lcd_set_addr_cgram(index * 8);
|
||||
for (uint8_t i = 0; i < 8; ++i) {
|
||||
lcd_write_data(array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Define a glyph */
|
||||
void lcd_define_glyph_pgm(const uint8_t index, const uint8_t* array)
|
||||
{
|
||||
lcd_set_addr_cgram(index * 8);
|
||||
for (uint8_t i = 0; i < 8; ++i) {
|
||||
lcd_write_data(pgm_read_byte(&array[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Set address in CGRAM */
|
||||
void lcd_set_addr_cgram(const uint8_t acg)
|
||||
{
|
||||
lcd_write_command(0b01000000 | ((acg) & 0b00111111));
|
||||
}
|
||||
|
||||
|
||||
/** Set address in DDRAM */
|
||||
void lcd_set_addr(const uint8_t add)
|
||||
{
|
||||
lcd_write_command(0b10000000 | ((add) & 0b01111111));
|
||||
}
|
||||
+48
-311
@@ -1,32 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
#include "calc.h"
|
||||
#include "pins.h"
|
||||
#include "nsdelay.h"
|
||||
|
||||
/*
|
||||
HD44780 LCD display driver - 4-bit mode
|
||||
|
||||
Required macros - pin settings (eg. B,3 or D,0)
|
||||
LCD pins are configured using a file lcd_config.h, which you
|
||||
have to add next to your main.c file.
|
||||
|
||||
LCD_PIN_RS
|
||||
LCD_PIN_RW
|
||||
LCD_PIN_E
|
||||
LCD_PIN_D7
|
||||
LCD_PIN_D6
|
||||
LCD_PIN_D5
|
||||
LCD_PIN_D4
|
||||
Content can be something like this:
|
||||
|
||||
#pragma once
|
||||
#include "lib/arduino_pins.h"
|
||||
#define LCD_RS D10
|
||||
#define LCD_RW D11
|
||||
#define LCD_E D12
|
||||
#define LCD_D4 D13
|
||||
#define LCD_D5 D14
|
||||
#define LCD_D6 D15
|
||||
#define LCD_D7 D16
|
||||
|
||||
Define those before including the header file.
|
||||
*/
|
||||
|
||||
// Commands for user
|
||||
#include <stdint.h>
|
||||
#include "lcd_config.h"
|
||||
|
||||
// Commands
|
||||
|
||||
// Clear screen (reset)
|
||||
#define LCD_CLEAR 0b00000001
|
||||
@@ -71,323 +68,63 @@
|
||||
#define LCD_IFACE_8BIT_2LINE 0b00111000
|
||||
|
||||
|
||||
// Start address of rows
|
||||
const uint8_t LCD_ROW_ADDR[] = {0x00, 0x40, 0x14, 0x54};
|
||||
|
||||
// prototypes
|
||||
|
||||
// --- PUBLIC API ---
|
||||
|
||||
/** Init the display */
|
||||
/** Initialize the display */
|
||||
void lcd_init();
|
||||
/** Write a command */
|
||||
void lcd_write_command(const uint8_t bb);
|
||||
/** Write data byte */
|
||||
void lcd_write_data(const uint8_t bb);
|
||||
/** Read busy flag & address */
|
||||
|
||||
/** Write an instruction byte */
|
||||
void lcd_write_command(uint8_t bb);
|
||||
|
||||
/** Write a data byte */
|
||||
void lcd_write_data(uint8_t bb);
|
||||
|
||||
/** Read BF & Address */
|
||||
uint8_t lcd_read_bf_addr();
|
||||
/** Read byte from ram */
|
||||
|
||||
/** Read CGRAM or DDRAM */
|
||||
uint8_t lcd_read_ram();
|
||||
/** Show string */
|
||||
void lcd_str(char* str);
|
||||
|
||||
/** Send a string to LCD */
|
||||
void lcd_str(char* str_p);
|
||||
|
||||
/** Sedn a char to LCD */
|
||||
void lcd_char(const char c);
|
||||
|
||||
/** Show string at X, Y */
|
||||
#define lcd_str_xy(x, y, str_p) do { lcd_xy((x), (y)); lcd_str((str_p)); } while(0)
|
||||
/** Show char */
|
||||
void lcd_char(const char c);
|
||||
|
||||
/** Show char at X, Y */
|
||||
#define lcd_char_xy(x, y, c) do { lcd_xy((x), (y)); lcd_char((c)); } while(0)
|
||||
/** Move cursor to X, Y */
|
||||
void lcd_xy(const uint8_t x, const uint8_t y);
|
||||
/** Set address in CGRAM */
|
||||
void lcd_set_addr_cgram(const uint8_t acg);
|
||||
/** Set address in DDRAM */
|
||||
void lcd_set_addr(const uint8_t add);
|
||||
/** Go home */
|
||||
void lcd_home();
|
||||
/** Clear the screen */
|
||||
void lcd_clear();
|
||||
|
||||
/** Set cursor */
|
||||
/** Set cursor position */
|
||||
void lcd_xy(const uint8_t x, const uint8_t y);
|
||||
|
||||
/** Set LCD cursor. If not enabled, only remember it. */
|
||||
#define CURSOR_NONE 0b00
|
||||
#define CURSOR_BAR 0b10
|
||||
#define CURSOR_BLINK 0b01
|
||||
#define CURSOR_BOTH 0b11
|
||||
void lcd_cursor(uint8_t type);
|
||||
|
||||
/** Disable / enable, preserving cursor */
|
||||
void lcd_disable();
|
||||
void lcd_enable();
|
||||
|
||||
/** Define a custom glyph */
|
||||
void lcd_define_glyph(const uint8_t index, const uint8_t* array);
|
||||
|
||||
|
||||
// Internals
|
||||
void _lcd_mode_r();
|
||||
void _lcd_mode_w();
|
||||
void _lcd_clk();
|
||||
void _lcd_wait_bf();
|
||||
void _lcd_write_byte(uint8_t bb);
|
||||
uint8_t _lcd_read_byte();
|
||||
|
||||
|
||||
// Write utilities
|
||||
#define _lcd_write_low(bb) _lcd_write_nibble((bb) & 0x0F)
|
||||
#define _lcd_write_high(bb) _lcd_write_nibble(((bb) & 0xF0) >> 4)
|
||||
#define _lcd_write_nibble(nib) do { \
|
||||
write_pin(LCD_PIN_D7, get_bit((nib), 3)); \
|
||||
write_pin(LCD_PIN_D6, get_bit((nib), 2)); \
|
||||
write_pin(LCD_PIN_D5, get_bit((nib), 1)); \
|
||||
write_pin(LCD_PIN_D4, get_bit((nib), 0)); \
|
||||
} while(0)
|
||||
|
||||
|
||||
|
||||
// 0 W, 1 R
|
||||
bool _lcd_mode;
|
||||
|
||||
/** Initialize the display */
|
||||
void lcd_init()
|
||||
{
|
||||
// configure pins as output
|
||||
as_output(LCD_PIN_E);
|
||||
as_output(LCD_PIN_RW);
|
||||
as_output(LCD_PIN_RS);
|
||||
_lcd_mode = 1; // force data pins to output
|
||||
_lcd_mode_w();
|
||||
|
||||
// Magic sequence to enter 4-bit mode
|
||||
_delay_ms(16);
|
||||
_lcd_write_nibble(0b0011);
|
||||
_lcd_clk();
|
||||
_delay_ms(5);
|
||||
_lcd_clk();
|
||||
_delay_ms(5);
|
||||
_lcd_clk();
|
||||
_delay_ms(5);
|
||||
_lcd_write_nibble(0b0010);
|
||||
_lcd_clk();
|
||||
_delay_us(100);
|
||||
|
||||
// Configure the display
|
||||
lcd_write_command(LCD_IFACE_4BIT_2LINE);
|
||||
lcd_write_command(LCD_DISABLE);
|
||||
lcd_write_command(LCD_CLEAR);
|
||||
lcd_write_command(LCD_MODE_INC);
|
||||
|
||||
lcd_enable();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Send a pulse on the ENABLE line */
|
||||
void _lcd_clk()
|
||||
{
|
||||
pin_up(LCD_PIN_E);
|
||||
delay_ns(420);
|
||||
pin_down(LCD_PIN_E);
|
||||
}
|
||||
|
||||
|
||||
/** Enter READ mode */
|
||||
void _lcd_mode_r()
|
||||
{
|
||||
if (_lcd_mode == 1) return; // already in R mode
|
||||
|
||||
pin_up(LCD_PIN_RW);
|
||||
|
||||
as_input_pu(LCD_PIN_D7);
|
||||
as_input_pu(LCD_PIN_D6);
|
||||
as_input_pu(LCD_PIN_D5);
|
||||
as_input_pu(LCD_PIN_D4);
|
||||
|
||||
_lcd_mode = 1;
|
||||
}
|
||||
|
||||
|
||||
/** Enter WRITE mode */
|
||||
void _lcd_mode_w()
|
||||
{
|
||||
if (_lcd_mode == 0) return; // already in W mode
|
||||
|
||||
pin_down(LCD_PIN_RW);
|
||||
|
||||
as_output(LCD_PIN_D7);
|
||||
as_output(LCD_PIN_D6);
|
||||
as_output(LCD_PIN_D5);
|
||||
as_output(LCD_PIN_D4);
|
||||
|
||||
_lcd_mode = 0;
|
||||
}
|
||||
|
||||
|
||||
/** Read a byte */
|
||||
uint8_t _lcd_read_byte()
|
||||
{
|
||||
_lcd_mode_r();
|
||||
|
||||
uint8_t res = 0;
|
||||
|
||||
_lcd_clk();
|
||||
res = (read_pin(LCD_PIN_D7) << 7) | (read_pin(LCD_PIN_D6) << 6) | (read_pin(LCD_PIN_D5) << 5) | (read_pin(LCD_PIN_D4) << 4);
|
||||
|
||||
_lcd_clk();
|
||||
res |= (read_pin(LCD_PIN_D7) << 3) | (read_pin(LCD_PIN_D6) << 2) | (read_pin(LCD_PIN_D5) << 1) | (read_pin(LCD_PIN_D4) << 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/** Write an instruction byte */
|
||||
void lcd_write_command(uint8_t bb)
|
||||
{
|
||||
_lcd_wait_bf();
|
||||
pin_down(LCD_PIN_RS); // select instruction register
|
||||
_lcd_write_byte(bb); // send instruction byte
|
||||
}
|
||||
|
||||
|
||||
/** Write a data byte */
|
||||
void lcd_write_data(uint8_t bb)
|
||||
{
|
||||
_lcd_wait_bf();
|
||||
pin_up(LCD_PIN_RS); // select data register
|
||||
_lcd_write_byte(bb); // send data byte
|
||||
}
|
||||
|
||||
|
||||
/** Read BF & Address */
|
||||
uint8_t lcd_read_bf_addr()
|
||||
{
|
||||
pin_down(LCD_PIN_RS);
|
||||
return _lcd_read_byte();
|
||||
}
|
||||
|
||||
|
||||
/** Read CGRAM or DDRAM */
|
||||
uint8_t lcd_read_ram()
|
||||
{
|
||||
pin_up(LCD_PIN_RS);
|
||||
return _lcd_read_byte();
|
||||
}
|
||||
|
||||
|
||||
/** Write a byte using the 8-bit interface */
|
||||
void _lcd_write_byte(uint8_t bb)
|
||||
{
|
||||
_lcd_mode_w(); // enter W mode
|
||||
|
||||
_lcd_write_high(bb);
|
||||
_lcd_clk();
|
||||
|
||||
_lcd_write_low(bb);
|
||||
_lcd_clk();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Wait until the device is ready */
|
||||
void _lcd_wait_bf()
|
||||
{
|
||||
uint8_t d = 0;
|
||||
while(d++ < 120 && lcd_read_bf_addr() & _BV(7))
|
||||
_delay_us(1);
|
||||
}
|
||||
|
||||
|
||||
/** Send a string to LCD */
|
||||
void lcd_str(char* str_p)
|
||||
{
|
||||
while (*str_p)
|
||||
lcd_char(*str_p++);
|
||||
}
|
||||
|
||||
|
||||
/** Sedn a char to LCD */
|
||||
void lcd_char(const char c)
|
||||
{
|
||||
lcd_write_data(c);
|
||||
}
|
||||
|
||||
|
||||
/** Set cursor position */
|
||||
void lcd_xy(const uint8_t x, const uint8_t y)
|
||||
{
|
||||
lcd_set_addr(LCD_ROW_ADDR[y] + (x));
|
||||
}
|
||||
|
||||
|
||||
uint8_t _lcd_old_cursor = CURSOR_NONE;
|
||||
bool _lcd_enabled = false;
|
||||
|
||||
/** Set LCD cursor. If not enabled, only remember it. */
|
||||
void lcd_cursor(uint8_t type)
|
||||
{
|
||||
_lcd_old_cursor = (type & CURSOR_BOTH);
|
||||
|
||||
if (_lcd_enabled) lcd_write_command(LCD_CURSOR_NONE | _lcd_old_cursor);
|
||||
}
|
||||
|
||||
|
||||
/** Display display (preserving cursor) */
|
||||
void lcd_disable()
|
||||
{
|
||||
lcd_write_command(LCD_DISABLE);
|
||||
_lcd_enabled = false;
|
||||
}
|
||||
|
||||
void lcd_disable();
|
||||
|
||||
/** Enable display (restoring cursor) */
|
||||
void lcd_enable()
|
||||
{
|
||||
_lcd_enabled = true;
|
||||
lcd_cursor(_lcd_old_cursor);
|
||||
}
|
||||
|
||||
void lcd_enable();
|
||||
|
||||
/** Go home */
|
||||
void lcd_home()
|
||||
{
|
||||
lcd_write_command(LCD_HOME);
|
||||
}
|
||||
|
||||
void lcd_home();
|
||||
|
||||
/** Clear the screen */
|
||||
void lcd_clear()
|
||||
{
|
||||
lcd_write_command(LCD_CLEAR);
|
||||
}
|
||||
|
||||
void lcd_clear();
|
||||
|
||||
/** Define a glyph */
|
||||
void lcd_define_glyph(const uint8_t index, const uint8_t* array)
|
||||
{
|
||||
lcd_set_addr_cgram(index * 8);
|
||||
for (uint8_t i = 0; i < 8; ++i) {
|
||||
lcd_write_data(array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_define_glyph(const uint8_t index, const uint8_t* array);
|
||||
|
||||
/** Define a glyph */
|
||||
void lcd_define_glyph_pgm(const uint8_t index, const uint8_t* array)
|
||||
{
|
||||
lcd_set_addr_cgram(index * 8);
|
||||
for (uint8_t i = 0; i < 8; ++i) {
|
||||
lcd_write_data(pgm_read_byte(&array[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_define_glyph_pgm(const uint8_t index, const uint8_t* array);
|
||||
|
||||
/** Set address in CGRAM */
|
||||
void lcd_set_addr_cgram(const uint8_t acg)
|
||||
{
|
||||
lcd_write_command(0b01000000 | ((acg) & 0b00111111));
|
||||
}
|
||||
|
||||
void lcd_set_addr_cgram(const uint8_t acg);
|
||||
|
||||
/** Set address in DDRAM */
|
||||
void lcd_set_addr(const uint8_t add)
|
||||
{
|
||||
lcd_write_command(0b10000000 | ((add) & 0b01111111));
|
||||
}
|
||||
void lcd_set_addr(const uint8_t add);
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
const uint8_t FADE_128[] = {
|
||||
0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4,
|
||||
5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 10, 10, 10, 11, 12, 13, 14,
|
||||
14, 15, 16, 17, 18, 20, 21, 22, 24, 26, 27, 28, 30, 31, 32, 34, 35, 36,
|
||||
38, 39, 40, 41, 42, 44, 45, 46, 48, 49, 50, 52, 54, 56, 58, 59, 61, 63,
|
||||
65, 67, 68, 69, 71, 72, 74, 76, 78, 80, 82, 85, 88, 90, 92, 95, 98, 100,
|
||||
103, 106, 109, 112, 116, 119, 122, 125, 129, 134, 138, 142, 147, 151,
|
||||
153, 156, 160, 163, 165, 170, 175, 180, 185, 190, 195, 200, 207, 214, 218,
|
||||
221, 225, 228, 232, 234, 241, 248, 254, 255
|
||||
};
|
||||
@@ -1,31 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
Ye Olde Control Structures
|
||||
*/
|
||||
|
||||
#include "loops.h"
|
||||
|
||||
#define whilst(what) while((what))
|
||||
#define when(what) if((what))
|
||||
#define otherwise else
|
||||
#define commence {
|
||||
#define then {
|
||||
#define cease }
|
||||
#define choose(what) switch((what))
|
||||
#define option case
|
||||
#define shatter break
|
||||
#define replay continue
|
||||
#define equals ==
|
||||
#define is ==
|
||||
#define be =
|
||||
#define over >
|
||||
#define above >
|
||||
#define under <
|
||||
#define below <
|
||||
#define let /**/
|
||||
#define raise(what) (what)++
|
||||
|
||||
#define number int
|
||||
|
||||
#warning "This is a joke. Do not use YeOlde.h in serious code!"
|
||||
Reference in New Issue
Block a user