avr-equeue

changeset 0:b1d590a201df

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 09 Jul 2014 08:58:46 +0300
parents
children 9cb1db5d0e7c
files .hgignore Makefile equeue.c runterm serial.c serial.h
diffstat 6 files changed, 382 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Wed Jul 09 08:58:46 2014 +0300
     1.3 @@ -0,0 +1,7 @@
     1.4 +\.o$
     1.5 +\.d$
     1.6 +\.swp$
     1.7 +\.hex$
     1.8 +\.eep$
     1.9 +\.map$
    1.10 +^equeue$
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/Makefile	Wed Jul 09 08:58:46 2014 +0300
     2.3 @@ -0,0 +1,38 @@
     2.4 +src = $(wildcard *.c)
     2.5 +obj = $(src:.c=.o)
     2.6 +bin = equeue
     2.7 +hex = $(bin).hex
     2.8 +eep = $(bin).eep
     2.9 +
    2.10 +mcu_gcc = atmega168
    2.11 +mcu_dude = m168
    2.12 +
    2.13 +CC = avr-gcc
    2.14 +OBJCOPY = avr-objcopy
    2.15 +
    2.16 +CFLAGS = -O2 -pedantic -Wall -mmcu=$(mcu_gcc) -DXTAL=14745600
    2.17 +LDFLAGS = -Wl,-Map,$(bin).map -mmcu=$(mcu_gcc) -lprintf_min
    2.18 +
    2.19 +.PHONY: all
    2.20 +all: $(hex) $(eep)
    2.21 +
    2.22 +$(bin): $(obj)
    2.23 +	$(CC) -o $@ $(obj) $(LDFLAGS)
    2.24 +
    2.25 +$(hex): $(bin)
    2.26 +	$(OBJCOPY) -j .text -j .data -O ihex -R .eeprom $< $@
    2.27 +
    2.28 +$(eep): $(bin)
    2.29 +	$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
    2.30 +
    2.31 +.PHONY: fuses
    2.32 +fuses:
    2.33 +	avrdude -c usbtiny -p $(mcu_dude) -U lfuse:w:0xc7:m
    2.34 +
    2.35 +.PHONY: program
    2.36 +program: $(hex)
    2.37 +	avrdude -c usbtiny -p $(mcu_dude) -e -U flash:w:$(hex)
    2.38 +
    2.39 +.PHONY: clean
    2.40 +clean:
    2.41 +	rm -f $(bin) $(obj) $(hex) $(eep) $(bin).map
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/equeue.c	Wed Jul 09 08:58:46 2014 +0300
     3.3 @@ -0,0 +1,225 @@
     3.4 +/* pin assignments
     3.5 + * C[0,5]	7seg [a,f]
     3.6 + * B1		7seg g
     3.7 + * B0		select display (0: units, 1: tens)
     3.8 + * B[2,3]	buttons with internal pullups
     3.9 + * D[6,7]	mode leds
    3.10 + */
    3.11 +
    3.12 +#ifdef XTAL
    3.13 +#define F_CLK	XTAL
    3.14 +#define F_CPU	XTAL
    3.15 +#else
    3.16 +#define F_CLK	1000000
    3.17 +#define F_CPU	1000000
    3.18 +#endif
    3.19 +
    3.20 +#include <stdio.h>
    3.21 +#include <avr/io.h>
    3.22 +#include <avr/interrupt.h>
    3.23 +#include <util/delay.h>
    3.24 +#include "serial.h"
    3.25 +
    3.26 +#define SHOW_TICKET_DELAY	256
    3.27 +
    3.28 +#define BN_NEXT			2
    3.29 +#define BN_TICKET		3
    3.30 +
    3.31 +#define LED_MODE_CUR	6
    3.32 +#define LED_MODE_TICKET	7
    3.33 +
    3.34 +void show(int num, int digit);
    3.35 +void disp_off(void);
    3.36 +void runcmd(const char *cmd);
    3.37 +
    3.38 +int show_ticket_cnt;
    3.39 +int cur_customer;
    3.40 +int last_ticket;
    3.41 +
    3.42 +#define MAX_INPUT_SIZE	256
    3.43 +char input[MAX_INPUT_SIZE];
    3.44 +int inp_cidx;
    3.45 +
    3.46 +int cmd_echo = 1;
    3.47 +
    3.48 +int main(void)
    3.49 +{
    3.50 +	int i = 0;
    3.51 +
    3.52 +	DDRB = 0xf3;	/* B: output except [2,3] */
    3.53 +	DDRC = 0xff;	/* C: output */
    3.54 +	DDRD = 0xff;	/* D: output */
    3.55 +
    3.56 +	PORTB = 0xff;	/* activate pullups and whatever */
    3.57 +	PORTC = 0xff;
    3.58 +	PORTD = 1 << LED_MODE_CUR;
    3.59 +
    3.60 +	PCICR = (1 << PCIE0);	/* enable pin change interrupt 2 */
    3.61 +	PCMSK0 = (1 << PCINT2) | (1 << PCINT3);
    3.62 +
    3.63 +	init_serial();
    3.64 +
    3.65 +	sei();
    3.66 +
    3.67 +	for(;;) {
    3.68 +		int digit = i & 1;
    3.69 +
    3.70 +		/* first grab any input from the serial port */
    3.71 +		while(have_input()) {
    3.72 +			int c = getchar();
    3.73 +			if(cmd_echo) {
    3.74 +				putchar(c);	/* echo back */
    3.75 +			}
    3.76 +			if(c == '\r' || c == '\n') {
    3.77 +				input[inp_cidx] = 0;
    3.78 +				runcmd(input);
    3.79 +				inp_cidx = 0;
    3.80 +			} else {
    3.81 +				input[inp_cidx++] = c;
    3.82 +			}
    3.83 +		}
    3.84 +
    3.85 +		disp_off();
    3.86 +		_delay_ms(1);
    3.87 +		PORTB = (PORTB & 0xfe) | digit;
    3.88 +		/*PORTD = (PORTD & 0xdf) | ((~digit) << 5);*/
    3.89 +		_delay_ms(1);
    3.90 +
    3.91 +		if(show_ticket_cnt > 0) {
    3.92 +			--show_ticket_cnt;
    3.93 +			show(last_ticket, digit);
    3.94 +			PORTD = (PORTD & 0x3f) | (1 << LED_MODE_TICKET);
    3.95 +		} else {
    3.96 +			show(cur_customer, digit);
    3.97 +			PORTD = (PORTD & 0x3f) | (1 << LED_MODE_CUR);
    3.98 +		}
    3.99 +
   3.100 +		++i;
   3.101 +		_delay_ms(1);
   3.102 +	}
   3.103 +}
   3.104 +
   3.105 +void issue_ticket(void)
   3.106 +{
   3.107 +	last_ticket++;
   3.108 +	show_ticket_cnt = SHOW_TICKET_DELAY;
   3.109 +	printf("ticket: %d\n", last_ticket);
   3.110 +}
   3.111 +
   3.112 +void next_customer(void)
   3.113 +{
   3.114 +	if(cur_customer < last_ticket) {
   3.115 +		cur_customer++;
   3.116 +		show_ticket_cnt = 0;
   3.117 +		printf("customer: %d\n", cur_customer);
   3.118 +	}
   3.119 +}
   3.120 +
   3.121 +ISR(PCINT0_vect)
   3.122 +{
   3.123 +	unsigned char inp = PINB;
   3.124 +
   3.125 +	if((inp & (1 << BN_TICKET)) == 0) {
   3.126 +		/* customer pressed the ticket button */
   3.127 +		issue_ticket();
   3.128 +	}
   3.129 +	if((inp & (1 << BN_NEXT)) == 0) {
   3.130 +		/* teller pressed the next customer button */
   3.131 +		next_customer();
   3.132 +	}
   3.133 +}
   3.134 +
   3.135 +enum {
   3.136 +	SEG_A = 1 << 0,
   3.137 +	SEG_B = 1 << 1,
   3.138 +	SEG_C = 1 << 2,
   3.139 +	SEG_D = 1 << 3,
   3.140 +	SEG_E = 1 << 4,
   3.141 +	SEG_F = 1 << 5,
   3.142 +	SEG_G = 1 << 6
   3.143 +};
   3.144 +
   3.145 +static const unsigned char seg[] = {
   3.146 +	SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F, /* 0 */
   3.147 +	SEG_B | SEG_C,							/* 1 */
   3.148 +	SEG_A | SEG_B | SEG_G | SEG_E | SEG_D,	/* 2 */
   3.149 +	SEG_A | SEG_B | SEG_G | SEG_C | SEG_D,	/* 3 */
   3.150 +	SEG_F | SEG_B | SEG_G | SEG_C,			/* 4 */
   3.151 +	SEG_A | SEG_F | SEG_G | SEG_C | SEG_D,	/* 5 */
   3.152 +	SEG_A | SEG_F | SEG_G | SEG_E | SEG_C | SEG_D,	/* 6 */
   3.153 +	SEG_A | SEG_B | SEG_C,					/* 7 */
   3.154 +	0xff,			/* 8 */
   3.155 +	SEG_A | SEG_B | SEG_F | SEG_G | SEG_C | SEG_D,	/* 9 */
   3.156 +	0
   3.157 +};
   3.158 +
   3.159 +void show(int num, int digit)
   3.160 +{
   3.161 +	int i, x = num;
   3.162 +	unsigned int bits;
   3.163 +
   3.164 +	for(i=0; i<digit; i++) {
   3.165 +		x /= 10;
   3.166 +	}
   3.167 +	x %= 10;
   3.168 +	bits = seg[x];
   3.169 +
   3.170 +	PORTC = (PORTC & 0xc0) | (bits & 0x3f);
   3.171 +	PORTB = (PORTB & 0xfd) | ((bits >> 5) & 2);
   3.172 +}
   3.173 +
   3.174 +void disp_off(void)
   3.175 +{
   3.176 +	PORTC = PORTC & 0xc0;
   3.177 +	PORTB = PORTB & 0xfd;
   3.178 +}
   3.179 +
   3.180 +#define VERSTR	\
   3.181 +	"Queue system v0.1 by John Tsiombikas <nuclear@member.fsf.org>"
   3.182 +
   3.183 +void runcmd(const char *cmd)
   3.184 +{
   3.185 +	switch(cmd[0]) {
   3.186 +	case 'e':
   3.187 +		cmd_echo = !cmd_echo;
   3.188 +		printf("OK,turning echo %s\n", cmd_echo ? "on" : "off");
   3.189 +		break;
   3.190 +
   3.191 +	case 'v':
   3.192 +		printf("OK,%s\n", VERSTR);
   3.193 +		break;
   3.194 +
   3.195 +	case 'r':
   3.196 +		printf("OK,reseting queues\n");
   3.197 +		cur_customer = 0;
   3.198 +		last_ticket = 0;
   3.199 +		show_ticket_cnt = 0;
   3.200 +		break;
   3.201 +
   3.202 +	case 't':
   3.203 +		printf("OK,ticket: %d\n", last_ticket);
   3.204 +		break;
   3.205 +
   3.206 +	case 'c':
   3.207 +		printf("OK,customer: %d\n", cur_customer);
   3.208 +		break;
   3.209 +
   3.210 +	case 'q':
   3.211 +		printf("OK,issuing queue ticket\n");
   3.212 +		issue_ticket();
   3.213 +		break;
   3.214 +
   3.215 +	case 'n':
   3.216 +		printf("OK,next customer\n");
   3.217 +		next_customer();
   3.218 +		break;
   3.219 +
   3.220 +	case 'h':
   3.221 +		printf("OK,commands: (e)cho, (v)ersion, (t)icket, (c)ustomer, "
   3.222 +				"(n)ext, (q)ueue, (r)eset, (h)elp.\n");
   3.223 +		break;
   3.224 +
   3.225 +	default:
   3.226 +		printf("ERR,unknown command: %s\n", cmd);
   3.227 +	}
   3.228 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/runterm	Wed Jul 09 08:58:46 2014 +0300
     4.3 @@ -0,0 +1,1 @@
     4.4 +minicom -b 9600 -D /dev/ttyUSB0 -o
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/serial.c	Wed Jul 09 08:58:46 2014 +0300
     5.3 @@ -0,0 +1,104 @@
     5.4 +#define F_CLK	XTAL
     5.5 +#define F_CPU	XTAL
     5.6 +
     5.7 +#include <stdio.h>
     5.8 +#include <avr/io.h>
     5.9 +#include <avr/interrupt.h>
    5.10 +#include <avr/power.h>
    5.11 +
    5.12 +#define BAUD		9600
    5.13 +#define UBRR_VAL	(F_CLK / 16 / BAUD - 1)
    5.14 +
    5.15 +static int uart_send_char(char c, FILE *fp);
    5.16 +static int uart_get_char(FILE *fp);
    5.17 +
    5.18 +#define BUF_SZ	32
    5.19 +static char outbuf[BUF_SZ];
    5.20 +static volatile int out_rd, out_wr;
    5.21 +
    5.22 +static char inbuf[BUF_SZ];
    5.23 +static volatile int in_rd, in_wr;
    5.24 +
    5.25 +static FILE std_stream = FDEV_SETUP_STREAM(uart_send_char, uart_get_char, _FDEV_SETUP_RW);
    5.26 +
    5.27 +
    5.28 +
    5.29 +void init_serial(void)
    5.30 +{
    5.31 +	power_usart0_enable();
    5.32 +
    5.33 +	/* make RXD (D0) an input and TXD (D1) an output */
    5.34 +	DDRD = (DDRD & 0xfc) | 2;
    5.35 +
    5.36 +	/* set baud generator timer reset value */
    5.37 +	UBRR0H = (unsigned char)(UBRR_VAL >> 8);
    5.38 +	UBRR0L = (unsigned char)UBRR_VAL;
    5.39 +
    5.40 +	/* enable rx/tx and recv interrupt */
    5.41 +	UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);
    5.42 +	/* set frame format: 8n1 */
    5.43 +	UCSR0C = 3 << UCSZ00;
    5.44 +
    5.45 +	stdin = stdout = stderr = &std_stream;
    5.46 +}
    5.47 +
    5.48 +int have_input(void)
    5.49 +{
    5.50 +	return in_wr != in_rd;
    5.51 +}
    5.52 +
    5.53 +#define NEXT_IDX(x)	(((x) + 1) % BUF_SZ)
    5.54 +static int uart_send_char(char c, FILE *fp)
    5.55 +{
    5.56 +	int next;
    5.57 +
    5.58 +	if(c == '\n') {
    5.59 +		uart_send_char('\r', fp);
    5.60 +	}
    5.61 +
    5.62 +	next = NEXT_IDX(out_wr);
    5.63 +	while(next == out_rd);
    5.64 +
    5.65 +	outbuf[out_wr] = c;
    5.66 +	out_wr = next;
    5.67 +
    5.68 +	/* enable the Tx data register empty interrupt */
    5.69 +	UCSR0B |= 1 << UDRIE0;
    5.70 +	return 0;
    5.71 +}
    5.72 +
    5.73 +static int uart_get_char(FILE *fp)
    5.74 +{
    5.75 +	char c;
    5.76 +	int next = NEXT_IDX(in_rd);
    5.77 +
    5.78 +	while(in_rd == in_wr);
    5.79 +
    5.80 +	c = inbuf[in_rd];
    5.81 +	in_rd = next;
    5.82 +	return c;
    5.83 +}
    5.84 +
    5.85 +ISR(USART_RX_vect)
    5.86 +{
    5.87 +	char c = UDR0;
    5.88 +
    5.89 +	if(c == '\r') {
    5.90 +		c = '\n';
    5.91 +	}
    5.92 +
    5.93 +	inbuf[in_wr] = c;
    5.94 +	in_wr = NEXT_IDX(in_wr);
    5.95 +}
    5.96 +
    5.97 +/* USART Tx data register empty (can send more data) */
    5.98 +ISR(USART_UDRE_vect)
    5.99 +{
   5.100 +	if(out_rd != out_wr) {
   5.101 +		UDR0 = outbuf[out_rd];
   5.102 +		out_rd = NEXT_IDX(out_rd);
   5.103 +	} else {
   5.104 +		/* no more data to send for now, disable the interrupt */
   5.105 +		UCSR0B &= ~(1 << UDRIE0);
   5.106 +	}
   5.107 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/serial.h	Wed Jul 09 08:58:46 2014 +0300
     6.3 @@ -0,0 +1,7 @@
     6.4 +#ifndef SERIAL_H_
     6.5 +#define SERIAL_H_
     6.6 +
     6.7 +void init_serial(void);
     6.8 +int have_input(void);
     6.9 +
    6.10 +#endif	/* SERIAL_H_ */