commit 299c89a9829546bfa8009608d4db0746b7d8ef10
parent 85f7fb0659abd49f51fbef5e30829f5d06526346
Author: Paco Esteban <paco@onna.be>
Date: Tue, 4 Dec 2018 21:51:50 +0100
firmware first version
Diffstat:
A | firmware/Makefile | | | 203 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | firmware/avr305.h | | | 104 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | firmware/blink.c | | | 333 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | 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 );