# optimize for size:
CFLAGS=-g -mmcu=$(MCU) -Wall -W -Os -mcall-prologues
# #-------------------
-.PHONY: test_lcd test_dac all main
+.PHONY: test_lcd test_dac all main ddcp-script
#
all: main.hex test_lcd.hex test_dac.hex
#
+ddcp-script: ddcp-script-setval ddcp-script-getval ddcp-script-ttyinit
+#
main: main.hex
#
test_lcd: test_lcd.hex
#
test_dac: test_dac.hex
echo "OK"
+#
+ddcp-script-setval: ddcp-script-setval.c
+ gcc -Wall -o ddcp-script-setval ddcp-script-setval.c
+ddcp-script-getval: ddcp-script-getval.c
+ gcc -Wall -o ddcp-script-getval ddcp-script-getval.c
+ddcp-script-ttyinit: ddcp-script-ttyinit.c
+ gcc -Wall -o ddcp-script-ttyinit ddcp-script-ttyinit.c
#-------------------
size:
avr-size *.elf
@echo " program using the avrdude programmer"
@echo " "
@echo "Usage: make clean"
- @echo " delete all generated files except the pre-compiled ones"
+ @echo " delete all generated files"
@echo "Test programs:"
@echo "Usage: make test_lcd|load_test_lcd|test_dac|load_test_dac"
@echo " compile and load test programs"
+ @echo "Usage: make ddcp-script-ttyinit"
+ @echo " compile unix program to set serial line speed such that one can use scripts to change settings"
#-------------------
main.hex: main.elf
$(OBJCOPY) -R .eeprom -O ihex main.elf main.hex
#-------------------
# fuse byte settings:
# Atmel AVR ATmega8
-# Fuse Low Byte = 0xe1 (1MHz internal), 0xe3 (4MHz internal), 0xe4 (8MHz internal)
+# Fuse Low Byte = 0xe1 (1MHz internal), 0xe4 (8MHz internal)
+# Fuse Low Byte with BOD = 0xa1 (1MHz internal), 0xa4 (8MHz internal)
# Fuse High Byte = 0xd9
# Factory default is 0xe1 for low byte and 0xd9 for high byte
# Check this with make rdfuses
$(LOADCMD) -p $(DUDECPUTYPE) -c stk500v2 -v -q
# use internal RC oscillator 8 Mhz (lf=0xe4 hf=0xd9)
fuses:
- $(LOADCMD) -p $(DUDECPUTYPE) -c stk500v2 -u -v -U lfuse:w:0xe4:m
+ $(LOADCMD) -p $(DUDECPUTYPE) -c stk500v2 -u -v -U lfuse:w:0xa4:m
$(LOADCMD) -p $(DUDECPUTYPE) -c stk500v2 -u -v -U hfuse:w:0xd9:m
fuse:
- $(LOADCMD) -p $(DUDECPUTYPE) -c stk500v2 -u -v -U lfuse:w:0xe4:m
+ $(LOADCMD) -p $(DUDECPUTYPE) -c stk500v2 -u -v -U lfuse:w:0xa4:m
$(LOADCMD) -p $(DUDECPUTYPE) -c stk500v2 -u -v -U hfuse:w:0xd9:m
#-------------------
clean:
- rm -f *.o *.map *.elf test*.hex main.hex
+ rm -f *.o *.map *.elf test*.hex main.hex ddcp-script-ttyinit ddcp-script-getval ddcp-script-setval
#-------------------
make
make load
-3) set the fuse bytes to 8MHz internal:
+3) set the fuse bytes to 8MHz internal with BOD:
make fuse
This should result in the following settings:
avrdude: Device signature = 0x1e9307
-avrdude: safemode: lfuse reads as E4
+avrdude: safemode: lfuse reads as A4
avrdude: safemode: hfuse reads as D9
+Fuse Low Byte details
+
+BODLEVEL Brown out detector trigger level = 1
+BODEN Brown out detector, 0=enable = 0
+SUT1 Select start-up time = 1
+SUT0 Select start-up time = 0
+CKSEL3 Select Clock source = 0
+CKSEL2 Select Clock source = 1
+CKSEL1 Select Clock source = 0
+CKSEL0 Select Clock source = 0
The make fuse needs to be done only once
unless you change the Atmega8 chip. make/make load
======================================================
You can e.g use putty under windows
http://www.chiark.greenend.org.uk/~sgtatham/putty/
-it supports as well serial connections
+it supports as well serial connections. The other common
+option under windows is HyperTerminal but it is more complicated
+to use than putty.
For Linux I can recommend picocom
http://code.google.com/p/picocom/
(use command picocom -l -b 9600 /dev/ttyUSB0)
+Another good serial terminal for linux is gtkterm
+http://www.jls-info.com/julien/linux/
+
+Serial port settings for the terminal:
port : Virtual com port (e.g /dev/ttyUSB1 or /dev/ttyUSB0
- or COM5 under windows or ... to whatever port the
- virtual com port maps)
-flowcontrol: none
+ or COM5 under windows or ... whatever port the
+ virtual com-port maps to)
+ Under linux or Mac you can use the command dmesg
+ after you have plugged in the USB cable to see to
+ which com-port/device the new virtual com port maps to.
+
baudrate : 9600
parity : none
+flowcontrol: none
+stopbits : 1
databits : 8
</pre>
<br>
<img src=screenshot-cmd-interface.gif>
<br>
+<br>
+At shop.tuxgraphics.org you can get an optically insulated
+USB to serial interface add-on kit such that your computer
+is galvanically separated from the power supply but still able
+to give commands. This enables you as well to use two power supplies
+to provide positive and negative supply voltages for e.g. an operational amplifier.
+
+<br>
+<br>
<pre>
+You can control the digital power supply by commands. A number
+of commands are provided for this purpose. They are at the moment
+available for Linux and Mac:
+
+
+ddcp-script-ttyinit - initialize the COM port
+ddcp-script-getval - get current values (same as you see on the LCD)
+ddcp-script-setval - send a command to the power supply
+
+ddcp-script-example.sh - an example shell script showing how to use
+ the above commands
+
-------------------------------------------------------------------
Copyright: GPL V2
Author: Guido Socher
-- Basic uart interface prompt, no remote control yet
digitaldcpower-0.6.2 -- 2010-06-26 Full UART command interface
+digitaldcpower-0.6.3 -- 2010-07-03 Accelerate UART command polling to
+ not loose characters when copied/pasted at high speed.
+ Line editing with backspace if terminal supports it.
+ Set BOD (brown out detector enable) fuse.
+ Script interface (ddcp-script)
-------------------------------------------------------------------
</pre>
#include <inttypes.h>
#include <stdlib.h>
#include "dac.h"
+#include "uart.h"
#include "hardware_settings.h"
if (channel==1){
// only after full measurement cycle
control_loop();
+ }else{
+ uart_poll_getchar_isr();
}
// end of interrupt handler
}
--- /dev/null
+#!/bin/sh
+# Example showing how to control the tuxgraphics digital power supply
+# by scripts.
+if [ -z "$1" ]; then
+ echo "USAGE: ddcp-script-example.sh /dev/ttyUSB0"
+ echo "or ddcp-script-example.sh /dev/ttyUSB1"
+ exit 0;
+fi
+dev="$1"
+# included the current directory to have access to the command
+# ddcp-script-getval to make testing easier. Normally you would
+# install ddcp-script-getval in /usr/bin and then delete the
+# line that sets the PATH
+PATH="${PATH}:."
+ddcp-script-ttyinit "$dev"
+echo "current settings are:"
+ddcp-script-getval "$dev"
+echo "setting voltage to 3.3 V"
+ddcp-script-setval "u=33" "$dev"
+echo "new settings are:"
+ddcp-script-getval "$dev"
+echo "wait one sec, it takes a moment for the display values to adjust as they are polled in the avr software"
+sleep 1
+echo "print settings again:"
+ddcp-script-getval "$dev"
--- /dev/null
+/* vim: set sw=8 ts=8 si et: */
+/*
+ * Linux software to communicate with the DDCP
+ * Written by Guido Socher
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+
+int main(int argc, char *argv[])
+{
+ char *device;
+ char c;
+ int c_cnt,state;
+ int fd;
+
+ if (argc != 2){
+ printf("USAGE: ddcp-script-getval /dev/ttyUSB0\n");
+ printf("or ddcp-script-getval /dev/ttyUSB1\n");
+ exit(0);
+ }
+ device=argv[1];
+
+ /* Set up io port correctly, and open it... */
+ fd = open(device, O_RDWR );
+ if (fd == -1) {
+ fprintf(stderr, "ERROR: open for %s failed.\n",device);
+ exit(1);
+ }
+ write(fd,"\r",1); // send empty line
+ usleep(100000); // commands are polled in the avr and it can take 100ms
+ write(fd,"\r",1); // send empty line
+ usleep(100000); // commands are polled in the avr and it can take 100ms
+ state=0;
+ while ((c_cnt=read(fd,&c,1))){
+ //printf(":0x%x:\n",c); // debug
+ if (c=='#') { // find begining of prompt
+ state=1;
+ }
+ if (state<1) continue;
+ if (c=='>') {
+ putc(c,stdout);
+ state=2;
+ }
+ if (state>1) break;
+ putc(c,stdout);
+ }
+ printf("\n");
+ close(fd);
+ usleep(100000); // commands are polled in the avr and it can take 100ms
+ return(0);
+}
--- /dev/null
+/* vim: set sw=8 ts=8 si et: */
+/*
+ * Linux software to communicate with the DDCP
+ * Written by Guido Socher
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <termios.h>
+
+int main(int argc, char *argv[])
+{
+ char *device;
+ char *str;
+ int fd;
+
+ if (argc != 3){
+ printf("USAGE: ddcp-script-setval \"u=33\" /dev/ttyUSB0\n");
+ printf("or ddcp-script-setval \"u=33\" /dev/ttyUSB1\n");
+ exit(0);
+ }
+ str=argv[1];
+ device=argv[2];
+
+ /* Set up io port correctly, and open it... */
+ fd = open(device, O_WRONLY );
+ if (fd == -1) {
+ fprintf(stderr, "ERROR: open for %s failed.\n",device);
+ exit(1);
+ }
+ write(fd,"\r",1);
+ usleep(100000); // commands are polled in the avr and it can take 100ms
+ write(fd,str,strlen(str));
+ write(fd,"\r",1);
+ close(fd);
+ usleep(150000);
+ return(0);
+}
--- /dev/null
+/* vim: set sw=8 ts=8 si et: */
+/* Linux software to set the speed on the serial line
+* Written by Guido Socher
+* run this program like this:
+* ttydevinit /dev/ttyUSB0 (for usb com1) and then use
+* cat > /dev/ttyUSB0 to write or cat /dev/ttyUSB0 to read the answers
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+
+int main(int argc, char *argv[])
+{
+ struct termios portset;
+ char *device;
+ int fd;
+
+ if (argc != 2){
+ printf("USAGE: ddcp-script-ttyinit /dev/ttyUSB0\n");
+ printf("or ddcp-script-ttyinit /dev/ttyUSB1\n");
+ exit(0);
+ }
+ device=argv[1];
+
+ /* Set up io port correctly, and open it... */
+ fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
+ if (fd == -1) {
+ fprintf(stderr, "ERROR: open for %s failed.\n",device);
+ exit(1);
+ }
+ tcgetattr(fd, &portset);
+ cfmakeraw(&portset);
+ cfsetospeed(&portset, B9600); /* speed */
+ //cfsetospeed(&portset, B115200); /* speed */
+ //cfsetospeed(&portset, B19200); /* speed */
+ tcsetattr(fd, TCSANOW, &portset);
+ close(fd);
+ return(0);
+}
/*********************************************
-* vim: set sw=8 ts=8 si :
+* vim: set sw=8 ts=8 si et :
* Author: Guido Socher, Copyright: GPL v3
* This is the main program for the digital dc power supply
*
#include "analog.h"
#include "hardware_settings.h"
-// change this when you compile:
-#define SWVERSION "ver: ddcp-0.6.2"
+// change this version string when you compile:
+#define SWVERSION "ver: ddcp-0.6.3"
//#define DEBUGDISP 1
//debug LED:
#define USE_UART 1
//
#ifdef USE_UART
-#define UARTSTRLEN 8
+#define UARTSTRLEN 10
static char uartstr[UARTSTRLEN+1];
static uint8_t uartstrpos=0;
static uint8_t uart_has_one_line=0;
void delay_ms_uartcheck(uint8_t ms)
// delay for a minimum of <ms>
{
- int ist_start_of_line=1;
+ uint8_t innerloop=1;
+ char c;
while(ms){
- _delay_ms(0.85);
#ifdef USE_UART
- if(uart_has_one_line==0 && uart_getchar_noblock(&uartstr[uartstrpos])){
- uart_sendchar(uartstr[uartstrpos]); // echo back
- if (uartstr[uartstrpos]=='\n'||uartstr[uartstrpos]=='\r'){
- uartstr[uartstrpos]='\0';
- uart_has_one_line=1;
- uart_sendchar('\n'); // the echo back puts a \r
- }
- // ignore leading white space on the line:
- if (!(uartstr[uartstrpos]==' ' || uartstr[uartstrpos]=='\t')){
- ist_start_of_line=0;
- uartstrpos++;
- }else{
- // white space
- if (ist_start_of_line==0){
- uartstrpos++;
- }
- }
- if (uartstrpos>UARTSTRLEN){
- uart_sendstr_P("\r\nERROR\r\n");
- uartstrpos=0; // empty buffer
- uartstr[uartstrpos]='\0'; // just print prompt
- uart_has_one_line=1;
- }
- }
+ if(uart_has_one_line==0 && uart_getchar_isr_noblock(&c)){
+ if (c=='\n') c='\r'; // Make unix scripting easier. A terminal, even under unix, does not send \n
+ // ignore any white space and characters we do not use:
+ if (!(c=='\b'||(c>='0'&&c<='z')||c==0x7f||c=='\r')){
+ goto NEXTCHAR;
+ }
+ if (c=='\r'){
+ uartstr[uartstrpos]='\0';
+ uart_sendchar('\r'); // the echo line end
+ uart_sendchar('\n'); // the echo line end
+ uart_has_one_line=1;
+ goto NEXTCHAR;
+ }
+ /*
+ // debug
+ itoa(c,buf,10);
+ uart_sendchar('\r'); // the echo line end
+ uart_sendchar('\n'); // the echo line end
+ uart_sendchar('|');uart_sendstr(buf);uart_sendchar('|');
+ uart_sendchar('\r'); // the echo line end
+ uart_sendchar('\n'); // the echo line end
+ */
+ if (c=='\b'){ // backspace
+ if (uartstrpos>0){
+ uartstrpos--;
+ uart_sendchar(c); // echo back
+ uart_sendchar(' '); // clear char on screen
+ uart_sendchar('\b');
+ }
+ }else if (c==0x7f){ // del
+ if (uartstrpos>0){
+ uartstrpos--;
+ uart_sendchar(c); // echo back
+ }
+ }else{
+ uart_sendchar(c); // echo back
+ uartstr[uartstrpos]=c;
+ uartstrpos++;
+ }
+ if (uartstrpos>UARTSTRLEN){
+ uart_sendstr_P("\r\nERROR\r\n");
+ uartstrpos=0; // empty buffer
+ uartstr[0]='\0'; // just print prompt
+ uart_has_one_line=1;
+ }
+ }
#endif
- ms--;
+NEXTCHAR:
+ innerloop--;
+ if (innerloop==0){
+ innerloop=45;
+ ms--;
+ }
}
}
// The integer must be a positive number.
// decimalpoint_pos can be 0, 1 or 2
static void int_to_dispstr(uint16_t inum,char *outbuf,int8_t decimalpoint_pos){
- int8_t i,j;
- char chbuf[8];
- itoa(inum,chbuf,10); // convert integer to string
- i=strlen(chbuf);
- if (i>3) i=3; //overflow protection
- strcpy(outbuf," 0"); //decimalpoint_pos==0
- if (decimalpoint_pos==1) strcpy(outbuf," 0.0");
- if (decimalpoint_pos==2) strcpy(outbuf,"0.00");
- j=4;
- while(i){
- outbuf[j-1]=chbuf[i-1];
- i--;
- j--;
- if (j==4-decimalpoint_pos){
- // jump over the pre-set dot
- j--;
- }
- }
+ int8_t i,j;
+ char chbuf[8];
+ itoa(inum,chbuf,10); // convert integer to string
+ i=strlen(chbuf);
+ if (i>3) i=3; //overflow protection
+ strcpy(outbuf," 0"); //decimalpoint_pos==0
+ if (decimalpoint_pos==1) strcpy(outbuf," 0.0");
+ if (decimalpoint_pos==2) strcpy(outbuf,"0.00");
+ j=4;
+ while(i){
+ outbuf[j-1]=chbuf[i-1];
+ i--;
+ j--;
+ if (j==4-decimalpoint_pos){
+ // jump over the pre-set dot
+ j--;
+ }
+ }
}
// convert voltage values to adc values, disp=10 is 1.0V
// ADC for voltage is 11bit:
static int16_t disp_u_to_adc(int16_t disp){
- return((int16_t)(((float)disp * 204.7) / (ADC_REF * U_DIVIDER )));
+ return((int16_t)(((float)disp * 204.7) / (ADC_REF * U_DIVIDER )));
}
// calculate the needed adc offset for voltage drop on the
// current measurement shunt (the shunt has about 0.75 Ohm =1/1.33 Ohm)
// use 1/1.2 instead of 1/1.3 because cables and connectors have as well
// a loss.
static int16_t disp_i_to_u_adc_offset(int16_t disp){
- return(disp_u_to_adc(disp/12));
+ return(disp_u_to_adc(disp/12));
}
// convert adc values to voltage values, disp=10 is 1.0V
// disp_i_val is needed to calculate the offset for the voltage drop over
// the current measurement shunt, voltage measurement is 11bit
static int16_t adc_u_to_disp(int16_t adcunits,int16_t disp_i_val){
- int16_t adcdrop;
- adcdrop=disp_i_to_u_adc_offset(disp_i_val);
- if (adcunits < adcdrop){
- return(0);
- }
- adcunits=adcunits-adcdrop;
- return((int16_t)((((float)adcunits /204.7)* ADC_REF * U_DIVIDER)+0.5));
+ int16_t adcdrop;
+ adcdrop=disp_i_to_u_adc_offset(disp_i_val);
+ if (adcunits < adcdrop){
+ return(0);
+ }
+ adcunits=adcunits-adcdrop;
+ return((int16_t)((((float)adcunits /204.7)* ADC_REF * U_DIVIDER)+0.5));
}
// convert adc values to current values, disp=10 needed to be printed
// by the printing function as 0.10 A, current measurement is 10bit
static int16_t disp_i_to_adc(int16_t disp){
- return((int16_t) (((disp * 10.23)* I_RESISTOR) / ADC_REF));
+ return((int16_t) (((disp * 10.23)* I_RESISTOR) / ADC_REF));
}
// convert adc values to current values, disp=10 needed to be printed
// by the printing function as 0.10 A, current measurement is 10bit
static int16_t adc_i_to_disp(int16_t adcunits){
- return((int16_t) (((float)adcunits* ADC_REF)/(10.23 * I_RESISTOR)+0.5));
+ return((int16_t) (((float)adcunits* ADC_REF)/(10.23 * I_RESISTOR)+0.5));
}
static void store_permanent(void){
- int16_t tmp;
- uint8_t changeflag=1;
- lcd_clrscr();
- if (eeprom_read_byte((uint8_t *)0x0) == 19){
- changeflag=0;
- // ok magic number matches accept values
- tmp=eeprom_read_word((uint16_t *)0x04);
- if (tmp != set_val[1]){
- changeflag=1;
- }
- tmp=eeprom_read_word((uint16_t *)0x02);
- if (tmp != set_val[0]){
- changeflag=1;
- }
- }
- if (changeflag){
- lcd_puts_P("setting stored");
- eeprom_write_byte((uint8_t *)0x0,19); // magic number
- eeprom_write_word((uint16_t *)0x02,set_val[0]);
- eeprom_write_word((uint16_t *)0x04,set_val[1]);
- }else{
- if (bpress> 2){
- // display software version after long press
- lcd_puts_P(SWVERSION);
- lcd_gotoxy(0,1);
- lcd_puts_P("tuxgraphics.org");
- }else{
- lcd_puts_P("already stored");
- }
- }
- delay_ms_uartcheck(200);
+ int16_t tmp;
+ uint8_t changeflag=1;
+ lcd_clrscr();
+ if (eeprom_read_byte((uint8_t *)0x0) == 19){
+ changeflag=0;
+ // ok magic number matches accept values
+ tmp=eeprom_read_word((uint16_t *)0x04);
+ if (tmp != set_val[1]){
+ changeflag=1;
+ }
+ tmp=eeprom_read_word((uint16_t *)0x02);
+ if (tmp != set_val[0]){
+ changeflag=1;
+ }
+ }
+ delay_ms_uartcheck(1); // check for uart without delay
+ if (changeflag){
+ lcd_puts_P("setting stored");
+ eeprom_write_byte((uint8_t *)0x0,19); // magic number
+ eeprom_write_word((uint16_t *)0x02,set_val[0]);
+ eeprom_write_word((uint16_t *)0x04,set_val[1]);
+ }else{
+ if (bpress> 2){
+ // display software version after long press
+ lcd_puts_P(SWVERSION);
+ lcd_gotoxy(0,1);
+ lcd_puts_P("tuxgraphics.org");
+ }else{
+ lcd_puts_P("already stored");
+ }
+ }
+ delay_ms_uartcheck(200);
+ delay_ms_uartcheck(200);
+ delay_ms_uartcheck(200);
}
// check the keyboard
static uint8_t check_buttons(void){
- uint8_t uartprint_ok=0;
- uint8_t cmdok=0;
+ uint8_t uartprint_ok=0;
+ uint8_t cmdok=0;
#ifdef USE_UART
- char buf[21];
+ char buf[21];
#endif
- //
+ //
#ifdef USE_UART
- if (uart_has_one_line){
+ if (uart_has_one_line){
if (uartstr[0]=='i' && uartstr[1]=='=' && uartstr[2]!='\0'){
set_val[0]=atoi(&uartstr[2]);
if(set_val[0]>I_MAX){
}
uartprint_ok=1;
}
- // version
- if (uartstr[0]=='v' && uartstr[1]=='e'){
- uart_sendstr_p(P(" "));
- uart_sendstr_p(P(SWVERSION));
- uart_sendstr_p(P("\r\n"));
- cmdok=1;
- }
- // store
- if (uartstr[0]=='s' && uartstr[1]=='t'){
- store_permanent();
+ // version
+ if (uartstr[0]=='v' && uartstr[1]=='e'){
+ uart_sendstr_p(P(" "));
+ uart_sendstr_p(P(SWVERSION));
+ uart_sendstr_p(P("\r\n"));
+ cmdok=1;
+ }
+ // store
+ if (uartstr[0]=='s' && uartstr[1]=='t'){
+ store_permanent();
uartprint_ok=1;
- }
+ }
if (uartstr[0]=='u' && uartstr[1]=='=' && uartstr[2]!='\0'){
set_val[1]=atoi(&uartstr[2]);
if(set_val[1]>U_MAX){
}
uartprint_ok=1;
}
- // help
- if (uartstr[0]=='h' || uartstr[0]=='H'){
- uart_sendstr_p(P(" Usage: u=V*10|i=mA/10|store|help|version\r\n"));
- uart_sendstr_p(P(" Examples:\r\n"));
- uart_sendstr_p(P(" set 6V: u=60\r\n"));
- uart_sendstr_p(P(" max 200mA: i=20\r\n"));
- cmdok=1;
- }
- if (uartprint_ok){
- cmdok=1;
- uart_sendstr_p(P(" ok\r\n"));
- }
- if (uartstr[0]!='\0' && cmdok==0){
- uart_sendstr_p(P(" command unknown\r\n"));
- }
-
- int_to_dispstr(measured_val[1],buf,1);
- uart_sendstr(buf);
- uart_sendchar('V');
- uart_sendchar(' ');
- uart_sendchar('[');
- int_to_dispstr(set_val[1],buf,1);
- uart_sendstr(buf);
- uart_sendchar(']');
- uart_sendchar(',');
- int_to_dispstr(measured_val[0],buf,2);
- uart_sendstr(buf);
- uart_sendchar('A');
- uart_sendchar(' ');
- uart_sendchar('[');
- int_to_dispstr(set_val[0],buf,2);
- uart_sendstr(buf);
- uart_sendchar(']');
- if (is_current_limit()){
- uart_sendchar('I');
- }else{
- uart_sendchar('U');
- }
- uart_sendchar('>');
- uart_has_one_line=0;
- uartstrpos=0;
- }
+ // help
+ if (uartstr[0]=='h' || uartstr[0]=='H'){
+ uart_sendstr_p(P(" Usage: u=V*10|i=mA/10|store|help|version\r\n"));
+ uart_sendstr_p(P(" Examples:\r\n"));
+ uart_sendstr_p(P(" set 6V: u=60\r\n"));
+ uart_sendstr_p(P(" max 200mA: i=20\r\n"));
+ cmdok=1;
+ }
+ if (uartprint_ok){
+ cmdok=1;
+ uart_sendstr_p(P(" ok\r\n"));
+ }
+ if (uartstr[0]!='\0' && cmdok==0){
+ uart_sendstr_p(P(" command unknown\r\n"));
+ }
+ uart_sendchar('#'); // marking char for script interface
+ int_to_dispstr(measured_val[1],buf,1);
+ uart_sendstr(buf);
+ uart_sendchar('V');
+ uart_sendchar(' ');
+ uart_sendchar('[');
+ int_to_dispstr(set_val[1],buf,1);
+ uart_sendstr(buf);
+ uart_sendchar(']');
+ uart_sendchar(',');
+ int_to_dispstr(measured_val[0],buf,2);
+ uart_sendstr(buf);
+ uart_sendchar('A');
+ uart_sendchar(' ');
+ uart_sendchar('[');
+ int_to_dispstr(set_val[0],buf,2);
+ uart_sendstr(buf);
+ uart_sendchar(']');
+ if (is_current_limit()){
+ uart_sendchar('I');
+ }else{
+ uart_sendchar('U');
+ }
+ uart_sendchar('>');
+ uartstrpos=0;
+ uart_has_one_line=0;
+ }
#endif
- if (check_u_button(&(set_val[1]))){
- if(set_val[1]>U_MAX){
- set_val[1]=U_MAX;
- }
- return(1);
- }
- if (check_i_button(&(set_val[0]))){
- if(set_val[0]>I_MAX){
- set_val[0]=I_MAX;
- }
- return(1);
- }
- if (check_store_button()){
- store_permanent();
- return(2);
- };
- return(0);
+ if (check_u_button(&(set_val[1]))){
+ if(set_val[1]>U_MAX){
+ set_val[1]=U_MAX;
+ }
+ return(1);
+ }
+ if (check_i_button(&(set_val[0]))){
+ if(set_val[0]>I_MAX){
+ set_val[0]=I_MAX;
+ }
+ return(1);
+ }
+ if (check_store_button()){
+ store_permanent();
+ return(2);
+ };
+ return(0);
}
int main(void)
{
- char out_buf[21];
- uint8_t i=0;
- uint8_t ilimit=0;
+ char out_buf[21];
+ uint8_t i=0;
+ uint8_t ilimit=0;
#ifndef USE_UART
- // debug led, you can not have an LED if you use the uart
- DDRD|= (1<<DDD0); // LED, enable PD0, LED as output
- LEDOFF;
+ // debug led, you can not have an LED if you use the uart
+ DDRD|= (1<<DDD0); // LED, enable PD0, LED as output
+ LEDOFF;
#endif
- init_dac();
- lcd_init();
- init_kbd();
- set_val[0]=15;set_val[1]=50; // 150mA and 5V
- if (eeprom_read_byte((uint8_t *)0x0) == 19){
- // ok magic number matches accept values
- set_val[1]=eeprom_read_word((uint16_t *)0x04);
- set_val[0]=eeprom_read_word((uint16_t *)0x02);
- }
+ init_dac();
+ lcd_init();
+ init_kbd();
+ set_val[0]=15;set_val[1]=50; // 150mA and 5V
+ if (eeprom_read_byte((uint8_t *)0x0) == 19){
+ // ok magic number matches accept values
+ set_val[1]=eeprom_read_word((uint16_t *)0x04);
+ set_val[0]=eeprom_read_word((uint16_t *)0x02);
+ // sanity check:
+ if (set_val[0]<0) set_val[0]=0;
+ if (set_val[1]<0) set_val[1]=0;
+ }
#ifdef USE_UART
- uart_init();
+ uart_init();
#endif
- sei();
- init_analog();
- while (1) {
- i++;
- // due to electrical interference we can get some
- // garbage onto the display especially if the power supply
- // source is not stable enough. We can remedy it a bit in
- // software with an ocasional reset:
- if (i==50){ // not every round to avoid flicker
- lcd_reset();
- i=0;
- }
- lcd_home();
- // current
- measured_val[0]=adc_i_to_disp(getanalogresult(0));
- set_val_adcUnits[0]=disp_i_to_adc(set_val[0]);
- set_target_adc_val(0,set_val_adcUnits[0]);
- // voltage
- measured_val[1]=adc_u_to_disp(getanalogresult(1),measured_val[0]);
- set_val_adcUnits[1]=disp_u_to_adc(set_val[1])+disp_i_to_u_adc_offset(measured_val[0]);
- set_target_adc_val(1,set_val_adcUnits[1]);
- ilimit=is_current_limit();
+ sei();
+ init_analog();
+ while (1) {
+ i++;
+ // due to electrical interference we can get some
+ // garbage onto the display especially if the power supply
+ // source is not stable enough. We can remedy it a bit in
+ // software with an ocasional reset:
+ if (i==50){ // not every round to avoid flicker
+ lcd_reset();
+ i=0;
+ }
+ lcd_home();
+ // current
+ measured_val[0]=adc_i_to_disp(getanalogresult(0));
+ set_val_adcUnits[0]=disp_i_to_adc(set_val[0]);
+ set_target_adc_val(0,set_val_adcUnits[0]);
+ // voltage
+ measured_val[1]=adc_u_to_disp(getanalogresult(1),measured_val[0]);
+ set_val_adcUnits[1]=disp_u_to_adc(set_val[1])+disp_i_to_u_adc_offset(measured_val[0]);
+ set_target_adc_val(1,set_val_adcUnits[1]);
+ ilimit=is_current_limit();
-
- // voltage
+
+ // voltage
#ifdef DEBUGDISP
- itoa(getanalogresult(1),out_buf,10);
+ itoa(getanalogresult(1),out_buf,10);
#else
- int_to_dispstr(measured_val[1],out_buf,1);
+ int_to_dispstr(measured_val[1],out_buf,1);
#endif
- lcd_puts(out_buf);
- lcd_puts("V [");
+ lcd_puts(out_buf);
+ lcd_puts("V [");
#ifdef DEBUGDISP
- itoa(set_val_adcUnits[1],out_buf,10);
+ itoa(set_val_adcUnits[1],out_buf,10);
#else
- int_to_dispstr(set_val[1],out_buf,1);
+ int_to_dispstr(set_val[1],out_buf,1);
#endif
- lcd_puts(out_buf);
- lcd_putc(']');
- if (!ilimit){
- // put a marker to show which value is currenlty limiting
- lcd_puts("<- ");
- }else{
- lcd_puts(" ");
- }
+ lcd_puts(out_buf);
+ lcd_putc(']');
+ delay_ms_uartcheck(1); // check for uart without delay
+ if (!ilimit){
+ // put a marker to show which value is currenlty limiting
+ lcd_puts("<- ");
+ }else{
+ lcd_puts(" ");
+ }
- // current
- lcd_gotoxy(0,1);
+ // current
+ lcd_gotoxy(0,1);
#ifdef DEBUGDISP
- itoa(getanalogresult(0),out_buf,10);
+ itoa(getanalogresult(0),out_buf,10);
#else
- int_to_dispstr(measured_val[0],out_buf,2);
+ int_to_dispstr(measured_val[0],out_buf,2);
#endif
- lcd_puts(out_buf);
- lcd_puts("A [");
+ lcd_puts(out_buf);
+ lcd_puts("A [");
#ifdef DEBUGDISP
- itoa(set_val_adcUnits[0],out_buf,10);
+ itoa(set_val_adcUnits[0],out_buf,10);
#else
- int_to_dispstr(set_val[0],out_buf,2);
+ int_to_dispstr(set_val[0],out_buf,2);
#endif
- lcd_puts(out_buf);
- lcd_putc(']');
- if (ilimit){
- // put a marker to show which value is currenlty limiting
- lcd_puts("<- ");
- }else{
- lcd_puts(" ");
- }
+ lcd_puts(out_buf);
+ lcd_putc(']');
+ if (ilimit){
+ // put a marker to show which value is currenlty limiting
+ lcd_puts("<- ");
+ }else{
+ lcd_puts(" ");
+ }
- // the buttons must be responsive but they must not
- // scroll too fast if pressed permanently
- if (check_buttons()==0){
- // no buttons pressed
- delay_ms_uartcheck(20);
- bpress=0;
- if (check_buttons()==0){
- // no buttons pressed
- delay_ms_uartcheck(20);
- }else{
- bpress++;
- delay_ms_uartcheck(180);
- }
- }else{
- // button press
- if (bpress > 10){
- // somebody pressed permanetly the button=>scroll fast
- delay_ms_uartcheck(30);
- }else{
- bpress++;
- delay_ms_uartcheck(180);
- }
- }
- }
- return(0);
+ // the buttons must be responsive but they must not
+ // scroll too fast if pressed permanently
+ if (check_buttons()==0){
+ // no buttons pressed
+ delay_ms_uartcheck(80);
+ bpress=0;
+ if (check_buttons()==0){
+ // no buttons pressed
+ delay_ms_uartcheck(80);
+ }else{
+ bpress++;
+ delay_ms_uartcheck(180);
+ delay_ms_uartcheck(180);
+ delay_ms_uartcheck(180);
+ delay_ms_uartcheck(180);
+ }
+ }else{
+ // button press
+ if (bpress > 10){
+ // somebody pressed permanetly the button=>scroll fast
+ delay_ms_uartcheck(120);
+ }else{
+ bpress++;
+ delay_ms_uartcheck(180);
+ delay_ms_uartcheck(180);
+ delay_ms_uartcheck(180);
+ delay_ms_uartcheck(180);
+ }
+ }
+ }
+ return(0);
}
--- /dev/null
+/*********************************************
+* vim: set sw=8 ts=8 si et :
+* Author: Guido Socher, Copyright: GPL v3
+* This is the main program for the digital dc power supply
+*
+* See http://www.tuxgraphics.org/electronics/
+*
+* Chip type : ATMEGA8
+* Clock frequency : Internal clock 8 Mhz
+*********************************************/
+#include <avr/io.h>
+#include <inttypes.h>
+#include <avr/interrupt.h>
+#define F_CPU 8000000UL // 8 MHz
+#include <util/delay.h>
+#include <stdlib.h>
+#include <string.h>
+#include <avr/eeprom.h>
+#include "lcd.h"
+#include "dac.h"
+#include "kbd.h"
+#include "uart.h"
+#include "analog.h"
+#include "hardware_settings.h"
+
+// change this version string when you compile:
+#define SWVERSION "ver: ddcp-0.6.3"
+//#define DEBUGDISP 1
+
+//debug LED:
+// set output to VCC, red LED off
+#define LEDOFF PORTD|=(1<<PORTD0)
+// set output to GND, red LED on
+#define LEDON PORTD&=~(1<<PORTD0)
+// to test the state of the LED
+#define LEDISOFF PORTD&(1<<PORTD0)
+//
+// the units are display units and work as follows: 100mA=10 5V=50
+// The function int_to_dispstr is used to convert the intenal values
+// into strings for the display
+static int16_t measured_val[2]={0,0};
+static int16_t set_val[2];
+// the set values but converted to ADC steps
+static int16_t set_val_adcUnits[2];
+static uint8_t bpress=0;
+// comment this out to use a debug LED on PD0 (RXD):
+#define USE_UART 1
+//
+#ifdef USE_UART
+#define UARTSTRLEN 10
+static char uartstr[UARTSTRLEN+1];
+static uint8_t uartstrpos=0;
+static uint8_t uart_has_one_line=0;
+#endif
+
+void delay_ms_uartcheck(uint8_t ms)
+// delay for a minimum of <ms>
+{
+ uint8_t innerloop=1;
+ while(ms){
+#ifdef USE_UART
+ if(uart_has_one_line==0 && uart_getchar_isr_noblock(&uartstr[uartstrpos])){
+ // ignore any white space:
+ if (uartstr[uartstrpos]==' ' || uartstr[uartstrpos]=='\t'){
+ goto NEXTCHAR;
+ }
+ if (uartstr[uartstrpos]=='\r'){
+ uartstr[uartstrpos]='\0';
+ uart_sendchar('\r'); // the echo line end
+ uart_sendchar('\n'); // the echo line end
+ //uart_sendchar('|'); uart_sendstr(&uartstr[0]);uart_sendchar('|'); //debug
+ uart_has_one_line=1;
+ goto NEXTCHAR;
+ }
+ uart_sendchar(uartstr[uartstrpos]);// echo back
+ /*
+ // debug
+ itoa(uartstr[uartstrpos],buf,10);
+ uart_sendchar('\r'); // the echo line end
+ uart_sendchar('\n'); // the echo line end
+ uart_sendstr(buf);
+ uart_sendchar('\r'); // the echo line end
+ uart_sendchar('\n'); // the echo line end
+ */
+ if (uartstr[uartstrpos]=='\b'){
+ if (uartstrpos>0){
+ uartstrpos--;
+ uart_sendchar(' '); // clear char on screen
+ uart_sendchar('\b');
+ }
+ }else if (uartstr[uartstrpos]==0x7f){ // del
+ if (uartstrpos>0){
+ uartstrpos--;
+ }
+ }else{
+ uartstrpos++;
+ }
+ if (uartstrpos>UARTSTRLEN){
+ uart_sendstr_P("\r\nERROR\r\n");
+ uartstrpos=0; // empty buffer
+ uartstr[0]='\0'; // just print prompt
+ uart_has_one_line=1;
+ }
+ }
+#endif
+NEXTCHAR:
+ innerloop--;
+ if (innerloop==0){
+ innerloop=45;
+ ms--;
+ }
+ }
+}
+
+// Convert an integer which is representing a float into a string.
+// Our display is always 4 digits long (including one
+// decimal point position). decimalpoint_pos defines
+// after how many positions from the right we set the decimal point.
+// The resulting string is fixed width and padded with leading space.
+//
+// decimalpoint_pos=2 sets the decimal point after 2 pos from the right:
+// e.g 74 becomes "0.74"
+// The integer should not be larger than 999.
+// The integer must be a positive number.
+// decimalpoint_pos can be 0, 1 or 2
+static void int_to_dispstr(uint16_t inum,char *outbuf,int8_t decimalpoint_pos){
+ int8_t i,j;
+ char chbuf[8];
+ itoa(inum,chbuf,10); // convert integer to string
+ i=strlen(chbuf);
+ if (i>3) i=3; //overflow protection
+ strcpy(outbuf," 0"); //decimalpoint_pos==0
+ if (decimalpoint_pos==1) strcpy(outbuf," 0.0");
+ if (decimalpoint_pos==2) strcpy(outbuf,"0.00");
+ j=4;
+ while(i){
+ outbuf[j-1]=chbuf[i-1];
+ i--;
+ j--;
+ if (j==4-decimalpoint_pos){
+ // jump over the pre-set dot
+ j--;
+ }
+ }
+}
+
+// convert voltage values to adc values, disp=10 is 1.0V
+// ADC for voltage is 11bit:
+static int16_t disp_u_to_adc(int16_t disp){
+ return((int16_t)(((float)disp * 204.7) / (ADC_REF * U_DIVIDER )));
+}
+// calculate the needed adc offset for voltage drop on the
+// current measurement shunt (the shunt has about 0.75 Ohm =1/1.33 Ohm)
+// use 1/1.2 instead of 1/1.3 because cables and connectors have as well
+// a loss.
+static int16_t disp_i_to_u_adc_offset(int16_t disp){
+ return(disp_u_to_adc(disp/12));
+}
+// convert adc values to voltage values, disp=10 is 1.0V
+// disp_i_val is needed to calculate the offset for the voltage drop over
+// the current measurement shunt, voltage measurement is 11bit
+static int16_t adc_u_to_disp(int16_t adcunits,int16_t disp_i_val){
+ int16_t adcdrop;
+ adcdrop=disp_i_to_u_adc_offset(disp_i_val);
+ if (adcunits < adcdrop){
+ return(0);
+ }
+ adcunits=adcunits-adcdrop;
+ return((int16_t)((((float)adcunits /204.7)* ADC_REF * U_DIVIDER)+0.5));
+}
+// convert adc values to current values, disp=10 needed to be printed
+// by the printing function as 0.10 A, current measurement is 10bit
+static int16_t disp_i_to_adc(int16_t disp){
+ return((int16_t) (((disp * 10.23)* I_RESISTOR) / ADC_REF));
+}
+// convert adc values to current values, disp=10 needed to be printed
+// by the printing function as 0.10 A, current measurement is 10bit
+static int16_t adc_i_to_disp(int16_t adcunits){
+ return((int16_t) (((float)adcunits* ADC_REF)/(10.23 * I_RESISTOR)+0.5));
+}
+
+static void store_permanent(void){
+ int16_t tmp;
+ uint8_t changeflag=1;
+ lcd_clrscr();
+ if (eeprom_read_byte((uint8_t *)0x0) == 19){
+ changeflag=0;
+ // ok magic number matches accept values
+ tmp=eeprom_read_word((uint16_t *)0x04);
+ if (tmp != set_val[1]){
+ changeflag=1;
+ }
+ tmp=eeprom_read_word((uint16_t *)0x02);
+ if (tmp != set_val[0]){
+ changeflag=1;
+ }
+ }
+ delay_ms_uartcheck(1); // check for uart without delay
+ if (changeflag){
+ lcd_puts_P("setting stored");
+ eeprom_write_byte((uint8_t *)0x0,19); // magic number
+ eeprom_write_word((uint16_t *)0x02,set_val[0]);
+ eeprom_write_word((uint16_t *)0x04,set_val[1]);
+ }else{
+ if (bpress> 2){
+ // display software version after long press
+ lcd_puts_P(SWVERSION);
+ lcd_gotoxy(0,1);
+ lcd_puts_P("tuxgraphics.org");
+ }else{
+ lcd_puts_P("already stored");
+ }
+ }
+ delay_ms_uartcheck(200);
+ delay_ms_uartcheck(200);
+ delay_ms_uartcheck(200);
+}
+
+// check the keyboard
+static uint8_t check_buttons(void){
+ uint8_t uartprint_ok=0;
+ uint8_t cmdok=0;
+#ifdef USE_UART
+ char buf[21];
+#endif
+ //
+#ifdef USE_UART
+ if (uart_has_one_line){
+ if (uartstr[0]=='i' && uartstr[1]=='=' && uartstr[2]!='\0'){
+ set_val[0]=atoi(&uartstr[2]);
+ if(set_val[0]>I_MAX){
+ set_val[0]=I_MAX;
+ }
+ if(set_val[0]<0){
+ set_val[0]=0;
+ }
+ uartprint_ok=1;
+ }
+ // version
+ if (uartstr[0]=='v' && uartstr[1]=='e'){
+ uart_sendstr_p(P(" "));
+ uart_sendstr_p(P(SWVERSION));
+ uart_sendstr_p(P("\r\n"));
+ cmdok=1;
+ }
+ // store
+ if (uartstr[0]=='s' && uartstr[1]=='t'){
+ store_permanent();
+ uartprint_ok=1;
+ }
+ if (uartstr[0]=='u' && uartstr[1]=='=' && uartstr[2]!='\0'){
+ set_val[1]=atoi(&uartstr[2]);
+ if(set_val[1]>U_MAX){
+ set_val[1]=U_MAX;
+ }
+ if(set_val[1]<0){
+ set_val[1]=0;
+ }
+ uartprint_ok=1;
+ }
+ // help
+ if (uartstr[0]=='h' || uartstr[0]=='H'){
+ uart_sendstr_p(P(" Usage: u=V*10|i=mA/10|store|help|version\r\n"));
+ uart_sendstr_p(P(" Examples:\r\n"));
+ uart_sendstr_p(P(" set 6V: u=60\r\n"));
+ uart_sendstr_p(P(" max 200mA: i=20\r\n"));
+ cmdok=1;
+ }
+ if (uartprint_ok){
+ cmdok=1;
+ uart_sendstr_p(P(" ok\r\n"));
+ }
+ if (uartstr[0]!='\0' && cmdok==0){
+ uart_sendstr_p(P(" command unknown\r\n"));
+ }
+
+ int_to_dispstr(measured_val[1],buf,1);
+ uart_sendstr(buf);
+ uart_sendchar('V');
+ uart_sendchar(' ');
+ uart_sendchar('[');
+ int_to_dispstr(set_val[1],buf,1);
+ uart_sendstr(buf);
+ uart_sendchar(']');
+ uart_sendchar(',');
+ int_to_dispstr(measured_val[0],buf,2);
+ uart_sendstr(buf);
+ uart_sendchar('A');
+ uart_sendchar(' ');
+ uart_sendchar('[');
+ int_to_dispstr(set_val[0],buf,2);
+ uart_sendstr(buf);
+ uart_sendchar(']');
+ if (is_current_limit()){
+ uart_sendchar('I');
+ }else{
+ uart_sendchar('U');
+ }
+ uart_sendchar('>');
+ uart_has_one_line=0;
+ uartstrpos=0;
+ }
+#endif
+ if (check_u_button(&(set_val[1]))){
+ if(set_val[1]>U_MAX){
+ set_val[1]=U_MAX;
+ }
+ return(1);
+ }
+ if (check_i_button(&(set_val[0]))){
+ if(set_val[0]>I_MAX){
+ set_val[0]=I_MAX;
+ }
+ return(1);
+ }
+ if (check_store_button()){
+ store_permanent();
+ return(2);
+ };
+ return(0);
+}
+
+int main(void)
+{
+ char out_buf[21];
+ uint8_t i=0;
+ uint8_t ilimit=0;
+
+#ifndef USE_UART
+ // debug led, you can not have an LED if you use the uart
+ DDRD|= (1<<DDD0); // LED, enable PD0, LED as output
+ LEDOFF;
+#endif
+
+ init_dac();
+ lcd_init();
+ init_kbd();
+ set_val[0]=15;set_val[1]=50; // 150mA and 5V
+ if (eeprom_read_byte((uint8_t *)0x0) == 19){
+ // ok magic number matches accept values
+ set_val[1]=eeprom_read_word((uint16_t *)0x04);
+ set_val[0]=eeprom_read_word((uint16_t *)0x02);
+ }
+#ifdef USE_UART
+ uart_init();
+#endif
+ sei();
+ init_analog();
+ while (1) {
+ i++;
+ // due to electrical interference we can get some
+ // garbage onto the display especially if the power supply
+ // source is not stable enough. We can remedy it a bit in
+ // software with an ocasional reset:
+ if (i==50){ // not every round to avoid flicker
+ lcd_reset();
+ i=0;
+ }
+ lcd_home();
+ // current
+ measured_val[0]=adc_i_to_disp(getanalogresult(0));
+ set_val_adcUnits[0]=disp_i_to_adc(set_val[0]);
+ set_target_adc_val(0,set_val_adcUnits[0]);
+ // voltage
+ measured_val[1]=adc_u_to_disp(getanalogresult(1),measured_val[0]);
+ set_val_adcUnits[1]=disp_u_to_adc(set_val[1])+disp_i_to_u_adc_offset(measured_val[0]);
+ set_target_adc_val(1,set_val_adcUnits[1]);
+ ilimit=is_current_limit();
+
+
+ // voltage
+#ifdef DEBUGDISP
+ itoa(getanalogresult(1),out_buf,10);
+#else
+ int_to_dispstr(measured_val[1],out_buf,1);
+#endif
+ lcd_puts(out_buf);
+ lcd_puts("V [");
+#ifdef DEBUGDISP
+ itoa(set_val_adcUnits[1],out_buf,10);
+#else
+ int_to_dispstr(set_val[1],out_buf,1);
+#endif
+ lcd_puts(out_buf);
+ lcd_putc(']');
+ delay_ms_uartcheck(1); // check for uart without delay
+ if (!ilimit){
+ // put a marker to show which value is currenlty limiting
+ lcd_puts("<- ");
+ }else{
+ lcd_puts(" ");
+ }
+
+ // current
+ lcd_gotoxy(0,1);
+#ifdef DEBUGDISP
+ itoa(getanalogresult(0),out_buf,10);
+#else
+ int_to_dispstr(measured_val[0],out_buf,2);
+#endif
+ lcd_puts(out_buf);
+ lcd_puts("A [");
+#ifdef DEBUGDISP
+ itoa(set_val_adcUnits[0],out_buf,10);
+#else
+ int_to_dispstr(set_val[0],out_buf,2);
+#endif
+ lcd_puts(out_buf);
+ lcd_putc(']');
+ if (ilimit){
+ // put a marker to show which value is currenlty limiting
+ lcd_puts("<- ");
+ }else{
+ lcd_puts(" ");
+ }
+
+ // the buttons must be responsive but they must not
+ // scroll too fast if pressed permanently
+ if (check_buttons()==0){
+ // no buttons pressed
+ delay_ms_uartcheck(80);
+ bpress=0;
+ if (check_buttons()==0){
+ // no buttons pressed
+ delay_ms_uartcheck(80);
+ }else{
+ bpress++;
+ delay_ms_uartcheck(180);
+ delay_ms_uartcheck(180);
+ delay_ms_uartcheck(180);
+ delay_ms_uartcheck(180);
+ }
+ }else{
+ // button press
+ if (bpress > 10){
+ // somebody pressed permanetly the button=>scroll fast
+ delay_ms_uartcheck(120);
+ }else{
+ bpress++;
+ delay_ms_uartcheck(180);
+ delay_ms_uartcheck(180);
+ delay_ms_uartcheck(180);
+ delay_ms_uartcheck(180);
+ }
+ }
+ }
+ return(0);
+}
+
#include "uart.h"
#define F_CPU 8000000UL // 8 MHz
+// a receiver stack:
+#define SENDSTACKSIZE 12
+static volatile char ustack[SENDSTACKSIZE];
+static volatile uint8_t stackpointer_end=0;
+static uint8_t stackpointer_start=0;
+
void uart_init(void)
{
unsigned int baud=51; // 9600 baud at 8MHz
}
+// call this function from interrupt to fill the
+// ustack reveiver buffer. We need this big buffer
+// to handle fast copy/paste of strings comming
+// into the UART
+void uart_poll_getchar_isr(void)
+{
+#ifdef VAR_88CHIP
+ if(!(UCSR0A & (1<<RXC0))) return;
+ ustack[stackpointer_end]=UDR0;
+#else
+ if(!(UCSRA & (1<<RXC))) return;
+ ustack[stackpointer_end]=UDR;
+#endif
+ stackpointer_end=(stackpointer_end+1) % SENDSTACKSIZE;
+}
+
+// get the characters out of the buffer which is filled by
+// the above interrupt function
+unsigned char uart_getchar_isr_noblock(char *returnval)
+{
+ if (stackpointer_start!=stackpointer_end){
+ *returnval=ustack[stackpointer_start];
+ stackpointer_start=(stackpointer_start+1) % SENDSTACKSIZE;
+ return(1);
+ }
+ return(0);
+}
+
+/*
// get a byte from rs232
// this function does a blocking read
char uart_getchar(void)
#endif
}
+*/
/*************************************************************************
Title: C include file for uart
Target: atmega8
+ Copyright: GPL, Guido Socher
***************************************************************************/
#ifndef UART_H
#define UART_H
#include <avr/pgmspace.h>
extern void uart_init(void);
-extern void uart_sendchar(char c);
-extern void uart_sendstr(char *s);
-extern void uart_sendstr_p(const prog_char *progmem_s);
+extern void uart_poll_getchar_isr(void); // call this periodically from interrupt, has a buffer bigger than one char
+extern unsigned char uart_getchar_isr_noblock(char *returnval); // get a char from buffer if available
+extern void uart_sendchar(char c); // blocking, no buffer
+extern void uart_sendstr(char *s); // blocking, no buffer
+extern void uart_sendstr_p(const prog_char *progmem_s); // blocking, no buffer
+/*
+// you can either use the above _isr functions or one of the
+// following two but you can not mix them.
extern char uart_getchar(void);
extern unsigned char uart_getchar_noblock(char *returnval);
extern void uart_flushRXbuf(void);
+*/
/*
** macros for automatically storing string constant in program memory