brymen_bm869s_ir_cable

Brymen 869s Serial PC-Comm DIY Cable.
git clone htps://git.onna.be/brymen_bm869s_ir_cable.git
Log | Files | Refs

commit 299c89a9829546bfa8009608d4db0746b7d8ef10
parent 85f7fb0659abd49f51fbef5e30829f5d06526346
Author: Paco Esteban <paco@onna.be>
Date:   Tue,  4 Dec 2018 21:51:50 +0100

firmware first version

Diffstat:
firmware/Makefile | 203+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
firmware/avr305.h | 104+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
firmware/blink.c | 333+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
firmware/bm869s.h | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 730 insertions(+), 0 deletions(-)

diff --git a/firmware/Makefile b/firmware/Makefile @@ -0,0 +1,203 @@ +##########------------------------------------------------------########## +########## Project-specific Details ########## +########## Check these every time you start a new project ########## +##########------------------------------------------------------########## + +MCU = attiny85 +AVR_TYPE = __AVR_ATtiny85__ +F_CPU = 8000000UL +BAUD = 9600UL +## Also try BAUD = 19200 or 38400 if you're feeling lucky. + +## A directory for common include files and the simple USART library. +## If you move either the current folder or the Library folder, you'll +## need to change this path to match. +#LIBDIR = ${HOME}/src/electronics/avr_libs +LIBDIR = + +##########------------------------------------------------------########## +########## Programmer Defaults ########## +########## Set up once, then forget about it ########## +########## (Can override. See bottom of file.) ########## +##########------------------------------------------------------########## + +PROGRAMMER_TYPE = usbasp +# extra arguments to avrdude: baud rate, chip type, -F flag, etc. +PROGRAMMER_ARGS = + +##########------------------------------------------------------########## +########## Program Locations ########## +########## Won't need to change if they're in your PATH ########## +##########------------------------------------------------------########## + +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +AVRSIZE = avr-size +AVRDUDE = avrdude + +##########------------------------------------------------------########## +########## Makefile Magic! ########## +########## Summary: ########## +########## We want a .hex file ########## +########## Compile source files into .elf ########## +########## Convert .elf file into .hex ########## +########## You shouldn't need to edit below. ########## +##########------------------------------------------------------########## + +## The name of your project (without the .c) +TARGET = blink +## Or name it automatically after the enclosing directory +# TARGET = $(lastword $(subst /, ,$(CURDIR))) + +# Object files: will find all .c/.h files in current directory +# and in LIBDIR. If you have any other (sub-)directories with code, +# you can add them in to SOURCES below in the wildcard statement. +SOURCES=$(wildcard *.c $(LIBDIR)/*.c $(CURDIR)/lib/*.c) +OBJECTS=$(SOURCES:.c=.o) +HEADERS=$(SOURCES:.c=.h) + +## Compilation options, type man avr-gcc if you're curious. +CPPFLAGS = -DF_CPU=$(F_CPU) -DBAUD=$(BAUD) -D$(AVR_TYPE) -I. -I$(LIBDIR) +CFLAGS = -Os -g -std=gnu99 -Wall +## Use short (8-bit) data types +CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +## Splits up object files per function +CFLAGS += -ffunction-sections -fdata-sections +LDFLAGS = -Wl,-Map,$(TARGET).map +## Optional, but often ends up with smaller code +LDFLAGS += -Wl,--gc-sections +## Relax shrinks code even more, but makes disassembly messy +## LDFLAGS += -Wl,--relax +## LDFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf +## LDFLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf +TARGET_ARCH = -mmcu=$(MCU) + +## Explicit pattern rules: +## To make .o files from .c files +%.o: %.c $(HEADERS) Makefile + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $@ $<; + +$(TARGET).elf: $(OBJECTS) + $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LDLIBS) -o $@ + +%.hex: %.elf + $(OBJCOPY) -j .text -j .data -O ihex $< $@ + +%.eeprom: %.elf + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +## These targets don't have files named after them +.PHONY: all disassemble disasm eeprom size clean squeaky_clean flash fuses + +all: $(TARGET).hex + +debug: + @echo + @echo "Source files:" $(SOURCES) + @echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD) + @echo + +# Optionally create listing file from .elf +# This creates approximate assembly-language equivalent of your code. +# Useful for debugging time-sensitive bits, +# or making sure the compiler does what you want. +disassemble: $(TARGET).lst + +disasm: disassemble + +# Optionally show how big the resulting program is +size: $(TARGET).elf + $(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf + +clean: + rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \ + $(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \ + $(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \ + $(TARGET).eeprom + +squeaky_clean: + rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ *.eeprom + +##########------------------------------------------------------########## +########## Programmer-specific details ########## +########## Flashing code to AVR using avrdude ########## +##########------------------------------------------------------########## + +flash: $(TARGET).hex + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$< + +## An alias +program: flash + +flash_eeprom: $(TARGET).eeprom + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$< + +avrdude_terminal: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt + +## If you've got multiple programmers that you use, +## you can define them here so that it's easy to switch. +## To invoke, use something like `make flash_arduinoISP` +flash_usbtiny: PROGRAMMER_TYPE = usbtiny +flash_usbtiny: PROGRAMMER_ARGS = # USBTiny works with no further arguments +flash_usbtiny: flash + +flash_usbasp: PROGRAMMER_TYPE = usbasp +flash_usbasp: PROGRAMMER_ARGS = # USBasp works with no further arguments +flash_usbasp: flash + +flash_arduinoISP: PROGRAMMER_TYPE = avrisp +flash_arduinoISP: PROGRAMMER_ARGS = -b 19200 -P /dev/ttyACM0 +## (for windows) flash_arduinoISP: PROGRAMMER_ARGS = -b 19200 -P com5 +flash_arduinoISP: flash + +flash_109: PROGRAMMER_TYPE = avr109 +flash_109: PROGRAMMER_ARGS = -b 9600 -P /dev/ttyUSB0 +flash_109: flash + +##########------------------------------------------------------########## +########## Fuse settings and suitable defaults ########## +##########------------------------------------------------------########## + +## Mega 48, 88, 168, 328 default values +# LFUSE = 0x62 +# HFUSE = 0xdf +## EFUSE = 0x00 # en realitat perdefecte he llegi 0xff +# EFUSE = 0xff +# per defecte per a l-atmega328p amb cristall 16MHz extern +LFUSE = 0xe2 +HFUSE = 0xdf +# EFUSE = 0x00 # en realitat perdefecte he llegi 0xff +EFUSE = 0xff + +## Generic +FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m + +fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \ + $(PROGRAMMER_ARGS) $(FUSE_STRING) +show_fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv + +## Called with no extra definitions, sets to defaults +set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m +set_default_fuses: fuses + +## Set the fuse byte for full-speed mode +## Note: can also be set in firmware for modern chips +set_fast_fuse: LFUSE = 0xE2 +set_fast_fuse: FUSE_STRING = -U lfuse:w:$(LFUSE):m +set_fast_fuse: fuses + +## Set the EESAVE fuse byte to preserve EEPROM across flashes +set_eeprom_save_fuse: HFUSE = 0xD7 +set_eeprom_save_fuse: FUSE_STRING = -U hfuse:w:$(HFUSE):m +set_eeprom_save_fuse: fuses + +## Clear the EESAVE fuse byte +clear_eeprom_save_fuse: FUSE_STRING = -U hfuse:w:$(HFUSE):m +clear_eeprom_save_fuse: fuses diff --git a/firmware/avr305.h b/firmware/avr305.h @@ -0,0 +1,104 @@ +#ifndef AVR305_H +#define AVR305_H + +/* See LICENSE file for copyright and license details. */ +#include <avr/io.h> +#include <avr/interrupt.h> + +//Set tx to PB2 / rx to PB1 +#define UART_Port _SFR_IO_ADDR(PORTB) +#define UART_Tx 0 +#define UART_Rx 1 + +//Define baudrate +#define BAUD_RATE 115200 + +//Calculate delays +#ifdef F_CPU +#define TXDELAY (((F_CPU/BAUD_RATE)-7 +1.5)/3) +#define RXDELAY (((F_CPU/BAUD_RATE)-5 +1.5)/3) +#else + #error CPU frequency F_CPU undefined +#endif + +void printc(char ch) { + uint8_t txdelay = TXDELAY; + uint8_t delayCount = 0; + + __asm__ __volatile__( + "0: cli\n\t" + " sbi %[uart_port]-1,%[uart_tx]\n\t" + " cbi %[uart_port],%[uart_tx]\n\t" + " in __tmp_reg__,%[uart_port]\n\t" + " ldi r25,3\n\t" + "1: mov %[delayCount],%[txdelay]\n\t" + "2: dec %[delayCount]\n\t" + " brne 2b\n\t" + " bst %[ch],0\n\t" + " bld __tmp_reg__,%[uart_tx]\n\t" + " lsr r25\n\t" + " ror %[ch]\n\t" + " out %[uart_port],__tmp_reg__\n\t" + " brne 1b\n\t" + : + [ch] "+r" (ch), + [delayCount] "+r" (delayCount) + : + [uart_port] "M" (UART_Port), + [uart_tx] "M" (UART_Tx), + [txdelay] "r" (txdelay) + : + "r25" + ); +} + +void serialPrint(const char *string) { + while(*string) { + printc(*string++); + } + sei(); +} + +void serialPrintln(const char *string) { + while(*string) { + printc(*string++); + } + printc('\r'); + printc('\n'); + sei(); +} + +char serialReadc() { + uint8_t rxdelay = RXDELAY; + uint8_t rxdelay15 = (RXDELAY*1.5)-2.5; + uint8_t delayCount = 0; + + __asm__ __volatile__( + "0: cbi %[uart_port]-1,%[uart_rx]\n\t" + " sbi %[uart_port],%[uart_rx]\n\t" + " mov %[delayCount],%[rxdelay15]\n\t" + " ldi %[rxdelay15],0x80\n\t" + "1: sbic %[uart_port]-2,%[uart_rx]\n\t" + " rjmp 1b\n\t" + " cli\n\t" + "2: subi %[delayCount], 1\n\t" + " brne 2b\n\t" + " mov %[delayCount],%[rxdelay]\n\t" + " sbic %[uart_port]-2,%[uart_rx]\n\t" + " sec\n\t" + " ror %[rxdelay15]\n\t" + " brcc 2b\n\t" + "3: dec %[delayCount]\n\t" + " brne 3b\n\t" + : + [rxdelay15] "+r" (rxdelay15), + [delayCount] "+r" (delayCount) + : + [uart_port] "M" (UART_Port), + [uart_rx] "M" (UART_Rx), + [rxdelay] "r" (rxdelay) + ); + return rxdelay15; +} + +#endif diff --git a/firmware/blink.c b/firmware/blink.c @@ -0,0 +1,333 @@ +#include <avr/io.h> +#include <util/delay.h> + +#include <bm869s.h> +#include <avr305.h> + +#define HIGH 1 +#define LOW 0 +#define IRTX PB3 +#define IRRX PB2 + +// Storage for the information received from the multimeter +#define BM_PBYTES 20 // 16 bytes with data and 4 bytes with other information +unsigned char bm[BM_PBYTES]; + +void digitalWrite( int pin, int state ) +{ + if ( state == HIGH ) { + PORTB |= ( 1 << pin ); + } else { + PORTB &= ~( 1 << pin ); + } +} + +unsigned char digitalRead( int pin ) +{ + return ( PINB & ( 1 << pin ) ); +} + +// Reads a byte from the multimeter +unsigned char getByte( void ) +{ + unsigned char result, mask; + + for ( mask = 1, result = 0; mask != 0; mask <<= 1 ) { + digitalWrite( IRTX, HIGH ); + _delay_us( 250 ); + + if ( PINB & ( 1 << IRRX ) ) result |= mask; + + digitalWrite( IRTX, LOW ); + _delay_us( 250 ); + } + + return result; +} + +// Reads 20 bytes from the multimeter +int readBM689s ( void ) +{ + unsigned int timeout; + unsigned char j; + + while ( IRRX == HIGH ); + + digitalWrite( IRTX, HIGH ); + _delay_ms( 10 ); + digitalWrite( IRTX, LOW ); + timeout = 0; + + while ( digitalRead( IRRX ) == LOW ) { + _delay_ms( 1 ); + timeout++; + + if ( timeout > 1000 ) break; + } + + if ( timeout <= 1000 ) { + for ( j = 0; j < BM_PBYTES; j++ ) bm[j] = getByte(); + + return 1; + } + + return 0; +} + +// Converts the digits information received into ASCII characters +char Decode_7seg ( unsigned char val ) +{ + switch ( val & 0xfe ) { + case LETTER_C: return'C'; break; + + case LETTER_d: return'd'; break; + + case LETTER_F: return'F'; break; + + case LETTER_i: return'i'; break; + + case LETTER_L: return'L'; break; + + case LETTER_o: return'o'; break; + + case BLANK: return' '; break; + + case DASH: return'-'; break; + + case NUMBER_0: return'0'; break; + + case NUMBER_1: return'1'; break; + + case NUMBER_2: return'2'; break; + + case NUMBER_3: return'3'; break; + + case NUMBER_4: return'4'; break; + + case NUMBER_5: return'5'; break; + + case NUMBER_6: return'6'; break; + + case NUMBER_7: return'7'; break; + + case NUMBER_8: return'8'; break; + + case NUMBER_9: return'9'; break; + + default: + return'?'; + break; + } +} + +// Sends via serial port whatever was read and decoded from the multimeter for the main display +void Send_Disp1 ( void ) +{ + char c; + + if ( ( ( bm[14] & Hz_1 ) == 0 ) && ( ( bm[14] & DUTY ) == 0 ) + && ( ( bm[14] & OHM ) == 0 ) && ( ( bm[13] & FARAD ) == 0 ) ) { + printc( bm[1]&negative_1 ? '-' : '+' ); + } + + printc( Decode_7seg( bm[2] ) ); + + if ( bm[3] & seg_p ) printc( '.' ); + + printc( Decode_7seg( bm[3] ) ); + + if ( bm[4] & seg_p ) printc( '.' ); + + printc( Decode_7seg( bm[4] ) ); + + if ( bm[5] & seg_p ) printc( '.' ); + + printc( Decode_7seg( bm[5] ) ); + + if ( bm[6] & seg_p ) printc( '.' ); + + printc( Decode_7seg( bm[6] ) ); + c = Decode_7seg( bm[7] ); + + if ( c != ' ' ) printc( c ); + + // Display the units of voltage or current + if ( ( bm[7] & V_1 ) || ( bm[13] & A_1 ) ) { + if ( ( bm[14] & m_1 ) || ( bm[14] & u_1 ) ) { + printc( 'E' ); + printc( '-' ); + printc( ( bm[14] & m_1 ) ? '3' : '6' ); + } + + printc( ' ' ); + + if ( bm[7] & V_1 ) + printc( 'V' ); + else + printc( 'A' ); + + if ( bm[0] & DC ) { + if ( bm[1] & AC_1 ) { + printc( 'R' ); + printc( 'M' ); + printc( 'S' ); + } else { + printc( 'D' ); + printc( 'C' ); + } + } else if ( bm[1] & AC_1 ) { + printc( 'A' ); + printc( 'C' ); + } + } + + // Frequency + if ( bm[14] & Hz_1 ) { + if ( ( bm[14] & k_1 ) || ( bm[14] & M_1 ) ) { + printc( 'E' ); + printc( '+' ); + + if ( bm[14] & k_1 ) + printc( '3' ); + else + printc( '6' ); + } + + printc( ' ' ); + printc( 'H' ); + printc( 'z' ); + } + + // Duty cycle + if ( bm[14] & DUTY ) { + printc( ' ' ); + printc( 'D' ); + printc( '%' ); + } + + // dB + if ( bm[14] & dB ) { + printc( ' ' ); + printc( 'd' ); + printc( 'B' ); + + if ( bm[14] & m_1 ) printc( 'm' ); + } + + // Resistance + if ( bm[14] & OHM ) { + if ( ( bm[14] & k_1 ) || ( bm[14] & M_1 ) ) { + printc( 'E' ); + printc( '+' ); + + if ( bm[14] & k_1 ) + printc( '3' ); + else + printc( '6' ); + } + + printc( ' ' ); + printc( 'O' ); + printc( 'H' ); + printc( 'M' ); + } + + // Capacitance + if ( bm[13] & FARAD ) { + if ( ( bm[13] & n ) || ( bm[14] & u_1 ) || ( bm[14] & m_1 ) ) { + printc( 'E' ); + printc( '-' ); + + if ( bm[13] & n ) printc( '9' ); + else if ( bm[14] & u_1 ) printc( '6' ); + else if ( bm[14] & m_1 ) printc( '3' ); + } + + printc( ' ' ); + printc( 'F' ); + } +} + +// Sends via serial port whatever was read and decoded from the multimeter for the second display +void Send_Disp2 ( void ) +{ + char c; + c = Decode_7seg( bm[9] ); + + if ( c != ' ' ) { + printc( bm[8]&negative_2 ? '-' : '+' ); + printc( Decode_7seg( bm[9] ) ); + + if ( bm[10] & seg_p ) printc( '.' ); + + printc( Decode_7seg( bm[10] ) ); + + if ( bm[11] & seg_p ) printc( '.' ); + + printc( Decode_7seg( bm[11] ) ); + + if ( bm[12] & seg_p ) printc( '.' ); + + printc( Decode_7seg( bm[12] ) ); + + // Display the units of voltage or current + if ( ( bm[13] & V_2 ) || ( bm[8] & A_2 ) ) { + if ( ( bm[8] & m_2 ) || ( bm[8] & u_2 ) ) { + printc( 'E' ); + printc( '-' ); + printc( ( bm[8] & m_2 ) ? '3' : '6' ); + } + + printc( ' ' ); + + if ( bm[13] & V_2 ) + printc( 'V' ); + else + printc( 'A' ); + + if ( bm[8] & AC_2 ) { + printc( 'A' ); + printc( 'C' ); + } else { + printc( 'D' ); + printc( 'C' ); + } + } + + if ( bm[13] & Hz_2 ) { + if ( ( bm[13] & k_2 ) || ( bm[13] & M_2 ) ) { + printc( 'E' ); + printc( '+' ); + + if ( bm[13] & k_2 ) + printc( '3' ); + else + printc( '6' ); + } + + printc( ' ' ); + printc( 'H' ); + printc( 'z' ); + } + } +} + +int main( void ) +{ + // Pin initialization + DDRB |= ( 1 << IRTX ); // port output + DDRB &= ~( 1 << IRRX ); // port input + PORTB &= ~( 1 << IRTX ); // set output ports to low + + while ( 1 ) { + readBM689s(); + /* Send_Disp1(); */ + /* Send_Disp2(); */ + + for ( unsigned char j = 0; j < BM_PBYTES; j++ ) printc( bm[j] ); + + _delay_ms( 200 ); + } + + return 0; +} diff --git a/firmware/bm869s.h b/firmware/bm869s.h @@ -0,0 +1,90 @@ +// The meaning of each of the bytes received from the multimeter +// Byte 0 +#define AUTO 0x01 +#define R 0x02 +#define C 0x04 +#define H 0x08 +#define DC 0x10 +#define MAX 0x20 +#define MIN 0x40 +#define AVG 0x80 +// Byte 1 +#define AC_1 0x01 +#define T1 0x02 +#define temp_minus 0x04 +#define T2_1 0x08 +#define bar_scale 0x10 +#define bar_negative 0x20 +#define VFD 0x40 +#define negative_1 0x80 +// Segments for all digits +#define seg_p 0x01 // Usually the dot of the previous number +#define seg_e 0x02 +#define seg_f 0x04 +#define seg_a 0x08 +#define seg_d 0x10 +#define seg_c 0x20 +#define seg_g 0x40 +#define seg_b 0x80 +// Byte 2: 7-SEG 1 +#define DELTA 0x01 +// Byte 3: 7-SEG 2 +// Byte 4: 7-SEG 3 +// Byte 5: 7-SEG 4 +// Byte 6: 7-SEG 5 +// Byte 7: 7-SEG 5 +#define V_1 0x01 +// Byte 8 +#define u_2 0x01 // u as in micro +#define m_2 0x02 // m as in milli +#define A_2 0x04 +#define ma20 0x08 +#define negative_2 0x10 +#define AC_2 0x20 +#define T2_2 0x40 +#define battery 0x80 +// Byte 9: 7-SEG 7 +#define sound 0x01 +// Byte 10: 7-SEG 8 +// Byte 11: 7-SEG 8 +// Byte 12: 7-SEG 8 +// Byte 13 +#define M_2 0x01 +#define k_2 0x02 +#define Hz_2 0x04 +#define V_2 0x08 +#define S 0x10 +#define FARAD 0x20 +#define n 0x40 +#define A_1 0x80 +// Byte 14 +#define Hz_1 0x01 +#define dB 0x02 +#define m_1 0x04 +#define u_1 0x08 +#define OHM 0x10 +#define M_1 0x20 +#define k_1 0x40 +#define DUTY 0x80 + +// The codes for some of letters and the numbers +#define LETTER_C 0x1e +#define LETTER_d 0xf2 +#define LETTER_F 0x4e +#define LETTER_i 0x20 +#define LETTER_L 0x16 +#define LETTER_o 0x72 +#define BLANK 0x00 +#define DASH 0x40 +#define NUMBER_0 0xbe +#define NUMBER_1 0xa0 +#define NUMBER_2 0xda +#define NUMBER_3 0xf8 +#define NUMBER_4 0xe4 +#define NUMBER_5 0x7c +#define NUMBER_6 0x7e +#define NUMBER_7 0xa8 +#define NUMBER_8 0xfe +#define NUMBER_9 0xfc + +char Decode_7seg ( unsigned char val );