From 1a0095a9aea4b0a4bd836e628abd49bc9c2fe123 Mon Sep 17 00:00:00 2001 From: Eddy Date: Sat, 21 Feb 2015 12:28:08 +0300 Subject: [PATCH] added 4-digit src --- voltmeters/src/4-digit/Makefile | 39 +++++ voltmeters/src/4-digit/interrupts.c | 156 ++++++++++++++++++ voltmeters/src/4-digit/interrupts.h | 148 +++++++++++++++++ voltmeters/src/4-digit/led.c | 237 ++++++++++++++++++++++++++++ voltmeters/src/4-digit/led.h | 43 +++++ voltmeters/src/4-digit/main.c | 152 ++++++++++++++++++ voltmeters/src/4-digit/main.h | 40 +++++ voltmeters/src/4-digit/testproj.bin | Bin 0 -> 3066 bytes voltmeters/src/5-digit/main.c | 2 - 9 files changed, 815 insertions(+), 2 deletions(-) create mode 100644 voltmeters/src/4-digit/Makefile create mode 100644 voltmeters/src/4-digit/interrupts.c create mode 100644 voltmeters/src/4-digit/interrupts.h create mode 100644 voltmeters/src/4-digit/led.c create mode 100644 voltmeters/src/4-digit/led.h create mode 100644 voltmeters/src/4-digit/main.c create mode 100644 voltmeters/src/4-digit/main.h create mode 100644 voltmeters/src/4-digit/testproj.bin diff --git a/voltmeters/src/4-digit/Makefile b/voltmeters/src/4-digit/Makefile new file mode 100644 index 0000000..7c22886 --- /dev/null +++ b/voltmeters/src/4-digit/Makefile @@ -0,0 +1,39 @@ +NAME=testproj +SDCC=sdcc +HEX2BIN=hex2bin + +CCFLAGS=-DSTM8S003 -I../ -I/usr/share/sdcc/include -mstm8 --out-fmt-ihx +LDFLAGS= -lstm8 -mstm8 --out-fmt-ihx +FLASHFLAGS=-cstlinkv2 -pstm8s003 + +SRC=$(wildcard *.c) +# ATTENTION: FIRST in list should be file with main() +OBJ=$(SRC:%.c=%.rel) +TRASH=$(OBJ) $(SRC:%.c=%.rst) $(SRC:%.c=%.asm) $(SRC:%.c=%.lst) +TRASH+=$(SRC:%.c=%.sym) $(NAME).ihx $(NAME).lk $(NAME).map +INDEPENDENT_HEADERS=../stm8l.h Makefile + +all: $(NAME).bin + +$(SRC) : %.c : %.h $(INDEPENDENT_HEADERS) + @touch $@ + @echo $@ + +%.h: ; + +clean: + rm -f $(TRASH) + +load: $(NAME).bin + stm8flash $(FLASHFLAGS) -w $(NAME).bin + +%.rel: %.c + $(SDCC) $(CCFLAGS) -c $< + +$(NAME).ihx: $(OBJ) + $(SDCC) $(LDFLAGS) $(OBJ) -o $(NAME).ihx + +$(NAME).bin: $(NAME).ihx + $(HEX2BIN) -p 00 $< + +.PHONY: all diff --git a/voltmeters/src/4-digit/interrupts.c b/voltmeters/src/4-digit/interrupts.c new file mode 100644 index 0000000..f90e30a --- /dev/null +++ b/voltmeters/src/4-digit/interrupts.c @@ -0,0 +1,156 @@ +/* + * interrupts.c + * + * Copyright 2015 Edward V. Emelianoff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "stm8l.h" +#include "interrupts.h" + +U8 ADC_ready = 0; // flag: data ready +int ADC_value = 0;// value of last ADC measurement + +// Top Level Interrupt +INTERRUPT_HANDLER(TLI_IRQHandler, 0){} + +// Auto Wake Up Interrupt +INTERRUPT_HANDLER(AWU_IRQHandler, 1){} + +// Clock Controller Interrupt +INTERRUPT_HANDLER(CLK_IRQHandler, 2){} + +// External Interrupt PORTA +INTERRUPT_HANDLER(EXTI_PORTA_IRQHandler, 3){} + +// External Interrupt PORTB +INTERRUPT_HANDLER(EXTI_PORTB_IRQHandler, 4){} + +// External Interrupt PORTC +INTERRUPT_HANDLER(EXTI_PORTC_IRQHandler, 5){} + +// External Interrupt PORTD +INTERRUPT_HANDLER(EXTI_PORTD_IRQHandler, 6){} + +// External Interrupt PORTE +INTERRUPT_HANDLER(EXTI_PORTE_IRQHandler, 7){} + +#ifdef STM8S903 +// External Interrupt PORTF +INTERRUPT_HANDLER(EXTI_PORTF_IRQHandler, 8){} +#endif // STM8S903 + +#if defined (STM8S208) || defined (STM8AF52Ax) +// CAN RX Interrupt routine. +INTERRUPT_HANDLER(CAN_RX_IRQHandler, 8){} + +// CAN TX Interrupt routine. +INTERRUPT_HANDLER(CAN_TX_IRQHandler, 9){} +#endif // STM8S208 || STM8AF52Ax + +// SPI Interrupt routine. +INTERRUPT_HANDLER(SPI_IRQHandler, 10){} + +// Timer1 Update/Overflow/Trigger/Break Interrupt +INTERRUPT_HANDLER(TIM1_UPD_OVF_TRG_BRK_IRQHandler, 11){ + if(TIM1_SR1 & TIM_SR1_UIF){ // update interrupt + Global_time++; // increase timer + } + TIM1_SR1 = 0; // clear all interrupt flags +} + +// Timer1 Capture/Compare Interrupt routine. +INTERRUPT_HANDLER(TIM1_CAP_COM_IRQHandler, 12){} + +#ifdef STM8S903 +// Timer5 Update/Overflow/Break/Trigger Interrupt +INTERRUPT_HANDLER(TIM5_UPD_OVF_BRK_TRG_IRQHandler, 13){} + +// Timer5 Capture/Compare Interrupt +INTERRUPT_HANDLER(TIM5_CAP_COM_IRQHandler, 14){} + +#else // STM8S208, STM8S207, STM8S105 or STM8S103 or STM8AF62Ax or STM8AF52Ax or STM8AF626x +// Timer2 Update/Overflow/Break Interrupt +INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13){} + +// Timer2 Capture/Compare Interrupt +// process soft I2C +INTERRUPT_HANDLER(TIM2_CAP_COM_IRQHandler, 14){ +} + +#endif // STM8S903 + +#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8S105) || \ + defined(STM8S005) || defined (STM8AF62Ax) || defined (STM8AF52Ax) || defined (STM8AF626x) +// Timer3 Update/Overflow/Break Interrupt +INTERRUPT_HANDLER(TIM3_UPD_OVF_BRK_IRQHandler, 15){} + +// Timer3 Capture/Compare Interrupt +INTERRUPT_HANDLER(TIM3_CAP_COM_IRQHandler, 16){} +#endif // STM8S208, STM8S207 or STM8S105 or STM8AF62Ax or STM8AF52Ax or STM8AF626x + +#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8S103) || \ + defined(STM8S003) || defined (STM8AF62Ax) || defined (STM8AF52Ax) || defined (STM8S903) +// UART1 TX Interrupt +INTERRUPT_HANDLER(UART1_TX_IRQHandler, 17){} + +// UART1 RX Interrupt +INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18){} +#endif // STM8S208 or STM8S207 or STM8S103 or STM8S903 or STM8AF62Ax or STM8AF52Ax + +// I2C Interrupt +INTERRUPT_HANDLER(I2C_IRQHandler, 19){} + +#if defined(STM8S105) || defined(STM8S005) || defined (STM8AF626x) +// UART2 TX interrupt +INTERRUPT_HANDLER(UART2_TX_IRQHandler, 20){} + +// UART2 RX interrupt +INTERRUPT_HANDLER(UART2_RX_IRQHandler, 21){} +#endif // STM8S105 or STM8AF626x + +#if defined(STM8S207) || defined(STM8S007) || defined(STM8S208) || defined (STM8AF52Ax) || defined (STM8AF62Ax) +// UART3 TX interrupt +INTERRUPT_HANDLER(UART3_TX_IRQHandler, 20){} + +// UART3 RX interrupt +INTERRUPT_HANDLER(UART3_RX_IRQHandler, 21){} +#endif // STM8S208 or STM8S207 or STM8AF52Ax or STM8AF62Ax + +#if defined(STM8S207) || defined(STM8S007) || defined(STM8S208) || defined (STM8AF52Ax) || defined (STM8AF62Ax) +// ADC2 interrupt +INTERRUPT_HANDLER(ADC2_IRQHandler, 22){} +#else +// ADC1 interrupt +INTERRUPT_HANDLER(ADC1_IRQHandler, 22){ + ADC_value = ADC_DRL; // in right-alignment mode we should first read LSB + ADC_value |= ADC_DRH << 8; + ADC_ready = 1; + ADC_CSR &= 0x3f; // clear EOC & AWD flags +} +#endif // STM8S208 or STM8S207 or STM8AF52Ax or STM8AF62Ax + +#ifdef STM8S903 +// Timer6 Update/Overflow/Trigger Interrupt +INTERRUPT_HANDLER(TIM6_UPD_OVF_TRG_IRQHandler, 23){} +#else // STM8S208, STM8S207, STM8S105 or STM8S103 or STM8AF52Ax or STM8AF62Ax or STM8AF626x +// Timer4 Update/Overflow Interrupt +INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23){} +#endif // STM8S903 + +// Eeprom EEC Interrupt +INTERRUPT_HANDLER(EEPROM_EEC_IRQHandler, 24){} diff --git a/voltmeters/src/4-digit/interrupts.h b/voltmeters/src/4-digit/interrupts.h new file mode 100644 index 0000000..ef9b70e --- /dev/null +++ b/voltmeters/src/4-digit/interrupts.h @@ -0,0 +1,148 @@ +/* + * interrupts.h + * + * Copyright 2014 Edward V. Emelianoff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#pragma once +#ifndef __INTERRUPTS_H__ +#define __INTERRUPTS_H__ + +#include "stm8l.h" + +extern U8 ADC_ready; // flag: data ready +extern U32 Global_time; // global time in ms +extern int ADC_value; // value of last ADC measurement + +// Top Level Interrupt +INTERRUPT_DEFINITION(TLI_IRQHandler, 0); + +// Auto Wake Up Interrupt +INTERRUPT_DEFINITION(AWU_IRQHandler, 1); + +// Clock Controller Interrupt +INTERRUPT_DEFINITION(CLK_IRQHandler, 2); + +// External Interrupt PORTA +INTERRUPT_DEFINITION(EXTI_PORTA_IRQHandler, 3); + +// External Interrupt PORTB +INTERRUPT_DEFINITION(EXTI_PORTB_IRQHandler, 4); + +// External Interrupt PORTC +INTERRUPT_DEFINITION(EXTI_PORTC_IRQHandler, 5); + +// External Interrupt PORTD +INTERRUPT_DEFINITION(EXTI_PORTD_IRQHandler, 6); + +// External Interrupt PORTE +INTERRUPT_DEFINITION(EXTI_PORTE_IRQHandler, 7); + +#ifdef STM8S903 +// External Interrupt PORTF +INTERRUPT_DEFINITION(EXTI_PORTF_IRQHandler, 8); +#endif // STM8S903 + +#if defined (STM8S208) || defined (STM8AF52Ax) +// CAN RX Interrupt routine. +INTERRUPT_DEFINITION(CAN_RX_IRQHandler, 8); + +// CAN TX Interrupt routine. +INTERRUPT_DEFINITION(CAN_TX_IRQHandler, 9); +#endif // STM8S208 || STM8AF52Ax + +// SPI Interrupt routine. +INTERRUPT_DEFINITION(SPI_IRQHandler, 10); + +// Timer1 Update/Overflow/Trigger/Break Interrupt +INTERRUPT_DEFINITION(TIM1_UPD_OVF_TRG_BRK_IRQHandler, 11); + +// Timer1 Capture/Compare Interrupt routine. +INTERRUPT_DEFINITION(TIM1_CAP_COM_IRQHandler, 12); + +#ifdef STM8S903 +// Timer5 Update/Overflow/Break/Trigger Interrupt +INTERRUPT_DEFINITION(TIM5_UPD_OVF_BRK_TRG_IRQHandler, 13); + +// Timer5 Capture/Compare Interrupt +INTERRUPT_DEFINITION(TIM5_CAP_COM_IRQHandler, 14); + +#else // STM8S208, STM8S207, STM8S105 or STM8S103 or STM8AF62Ax or STM8AF52Ax or STM8AF626x +// Timer2 Update/Overflow/Break Interrupt +INTERRUPT_DEFINITION(TIM2_UPD_OVF_BRK_IRQHandler, 13); + +// Timer2 Capture/Compare Interrupt +INTERRUPT_DEFINITION(TIM2_CAP_COM_IRQHandler, 14); +#endif // STM8S903 + +#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8S105) || \ + defined(STM8S005) || defined (STM8AF62Ax) || defined (STM8AF52Ax) || defined (STM8AF626x) +// Timer3 Update/Overflow/Break Interrupt +INTERRUPT_DEFINITION(TIM3_UPD_OVF_BRK_IRQHandler, 15); + +// Timer3 Capture/Compare Interrupt +INTERRUPT_DEFINITION(TIM3_CAP_COM_IRQHandler, 16); +#endif // STM8S208, STM8S207 or STM8S105 or STM8AF62Ax or STM8AF52Ax or STM8AF626x + +#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8S103) || \ + defined(STM8S003) || defined (STM8AF62Ax) || defined (STM8AF52Ax) || defined (STM8S903) +// UART1 TX Interrupt +INTERRUPT_DEFINITION(UART1_TX_IRQHandler, 17); + +// UART1 RX Interrupt +INTERRUPT_DEFINITION(UART1_RX_IRQHandler, 18); +#endif // STM8S208 or STM8S207 or STM8S103 or STM8S903 or STM8AF62Ax or STM8AF52Ax + +// I2C Interrupt +INTERRUPT_DEFINITION(I2C_IRQHandler, 19); + +#if defined(STM8S105) || defined(STM8S005) || defined (STM8AF626x) +// UART2 TX interrupt +INTERRUPT_DEFINITION(UART2_TX_IRQHandler, 20); + +// UART2 RX interrupt +INTERRUPT_DEFINITION(UART2_RX_IRQHandler, 21); +#endif // STM8S105 or STM8AF626x + +#if defined(STM8S207) || defined(STM8S007) || defined(STM8S208) || defined (STM8AF52Ax) || defined (STM8AF62Ax) +// UART3 TX interrupt +INTERRUPT_DEFINITION(UART3_TX_IRQHandler, 20); + +// UART3 RX interrupt +INTERRUPT_DEFINITION(UART3_RX_IRQHandler, 21); +#endif // STM8S208 or STM8S207 or STM8AF52Ax or STM8AF62Ax + +#if defined(STM8S207) || defined(STM8S007) || defined(STM8S208) || defined (STM8AF52Ax) || defined (STM8AF62Ax) +// ADC2 interrupt +INTERRUPT_DEFINITION(ADC2_IRQHandler, 22); +#else // STM8S105, STM8S103 or STM8S903 or STM8AF626x +// ADC1 interrupt +INTERRUPT_DEFINITION(ADC1_IRQHandler, 22); +#endif // STM8S208 or STM8S207 or STM8AF52Ax or STM8AF62Ax + +#ifdef STM8S903 +// Timer6 Update/Overflow/Trigger Interrupt +INTERRUPT_DEFINITION(TIM6_UPD_OVF_TRG_IRQHandler, 23); +#else // STM8S208, STM8S207, STM8S105 or STM8S103 or STM8AF52Ax or STM8AF62Ax or STM8AF626x +// Timer4 Update/Overflow Interrupt +INTERRUPT_DEFINITION(TIM4_UPD_OVF_IRQHandler, 23); +#endif // STM8S903 + +// Eeprom EEC Interrupt +INTERRUPT_DEFINITION(EEPROM_EEC_IRQHandler, 24); + +#endif // __INTERRUPTS_H__ diff --git a/voltmeters/src/4-digit/led.c b/voltmeters/src/4-digit/led.c new file mode 100644 index 0000000..3b1e1eb --- /dev/null +++ b/voltmeters/src/4-digit/led.c @@ -0,0 +1,237 @@ +/* + * led.c + * + * Copyright 2014 Edward V. Emelianoff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "stm8l.h" +#include "led.h" + +/* + * bits no 7 6 5 4 3 2 1 0 + * dec value 128 64 32 16 8 4 2 1 + */ + +/********** current variant **********/ +/* + * One digit: TABLE: + * ***A*** 0 1 2 3 4 5 6 7 8 9 A B C D E F - h + * * * (F) PA1 0 1 1 1 0 0 0 1 0 0 0 0 0 1 0 0 1 0 + * F B (B) PB4 0 0 0 0 0 1 1 0 0 0 0 1 1 0 1 1 1 1 + * * * (A) PB5 0 1 0 0 1 0 0 0 0 0 0 1 0 1 0 0 1 1 + * ***G*** (G) PC3 1 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 + * * * (C) PC4 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 1 1 0 + * E C (DP)PC5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + * * * ** (D) PC6 0 1 0 0 1 0 0 1 0 0 1 0 0 0 0 1 1 1 + * ***D*** *DP* (E) PC7 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 0 1 0 + * ** + */ + +/* + * Number of digit on indicator with common anode + * digis 0..3: PA3, PD6, PD4, PD1 + */ +#define CLEAR_ANODES() do{PD_ODR &= ~(0x52);PA_ODR &= ~(0x08);}while(0) + +/************* arrays for ports *************/ +// PA, mask: 0x02, PA1 +static U8 PA_bits[18] = {0,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,0}; +#define PA_BLANK 0x02 +// PB, mask: 0x30, PB4:0x10=16, PB5:0x20=32 +#define PB_BLANK 0x30 +static U8 PB_bits[18] = {0,32,0,0,32,16,16,0,0,0,0,48,16,32,16,16,48,48}; +// PC, mask: 0xF8, PC3:0x08=8, PC4:0x10=16, PC5:0x20=32, PC6:0x40=64, PC7:0x80=128 +#define PC_BLANK 0xF8 +static U8 PC_bits[18] = {40,232,48,160,224,160,32,232,32,160,96,32,56,32,48,112,240,96}; + +/** + * Setup for writing a letter + * @param ltr - letter (0..17 for 0..F, - or h | 0x80 for DP, any other value for 'space') + */ +void write_letter(U8 ltr){ + U8 L = ltr & 0x7f; + // first turn all off + CLEAR_ANODES(); + // light up all segments + PA_ODR &= ~PA_BLANK; + PB_ODR &= ~PB_BLANK; + PC_ODR &= ~PC_BLANK; + // now clear spare segments + if(L < 18){ // letter + PA_ODR |= PA_bits[L]; + PB_ODR |= PB_bits[L]; + PC_ODR |= PC_bits[L]; + }else{ // space - turn all OFF + PA_ODR |= PA_BLANK; + PB_ODR |= PB_BLANK; + PC_ODR |= PC_BLANK; + } + if(ltr & 0x80){ // DP + PC_ODR &= ~GPIO_PIN5; + } +} + +/** + * Turn on anode power for digit N (0..3: PA3, PD6, PD4, PD1 -- A0x08, D0x40, D0x10, D0x02) + * @param N - number of digit (0..3), if other - no action (display off) + * @return + */ +void light_up_digit(U8 N){ + switch(N){ + case 0: + PA_ODR |= 0x08; + break; + case 1: + PD_ODR |= 0x40; + break; + case 2: + PD_ODR |= 0x10; + break; + case 3: + PD_ODR |= 0x02; + break; + } +} + +static U8 display_buffer[4] = {' ',' ',' ',' '}; // blank by default +static U8 N_current = 0; // current digit to display + +/** + * fills buffer to display + * @param str - string to display, contains "0..f" for digits, " " for space, "." for DP + * for example: " 1.22" or "h1ab" (something like "0...abc" equivalent to "0.abc" + * register independent! + * any other letter would be omitted + * if NULL - fill buffer with spaces + */ +void set_display_buf(char *str){ + U8 B[4]; + char ch, M = 0, i; + N_current = 0; // refresh current digit number + // empty buffer + for(i = 0; i < 4; i++) + display_buffer[i] = ' '; + if(!str) return; + i = 0; + for(;(ch = *str) && (i < 4); str++){ + M = 0; + if(ch > '/' && ch < ':'){ // digit + M = '0'; + }else if(ch > '`' & ch < 'g'){ // a..f + M = 'a' - 10; + }else if(ch > '@' & ch < 'G'){ // A..F + M = 'A' - 10; + }else if(ch == '-'){ // minus + M = '-' - 16; + }else if(ch == 'h'){ // hex + M = 'h' - 17; + }else if(ch == 'H'){ // hex + M = 'H' - 17; + }else if(ch == '.'){ // DP, set it to previous char + if(i == 0){ // word starts from '.' - make a space with point + B[0] = 0xff; + }else{ // set point for previous character + B[i-1] |= 0x80; + } + continue; + }else if(ch != ' '){ // bad character - continue + continue; + } + B[i] = ch - M; + i++; + } + // now make align to right + ch = 3; + for(M = i-1; M > -1; M--, ch--){ + display_buffer[ch] = B[M]; + } +} + +/** + * Show Nth digit of buffer (function ran by timer) + * @param N - number of digit in buffer (0..3) + */ +void show_buf_digit(U8 N){ + if(N > 3) return; + write_letter(display_buffer[N]); + light_up_digit(N); +} + +/** + * Show next digit - function calls from main() by some system time value amount + */ +void show_next_digit(){ + show_buf_digit(N_current++); + if(N_current > 3) N_current = 0; +} + +/** + * Turn off current digit: to change display brightness + */ +void lights_off(){ + U8 N; + if(N_current) N = N_current - 1; + else N = 3; + light_up_digit(N); +} + +/** + * convert integer value i into string and display it + * @param i - value to display, -999 <= i <= 9999, if wrong, displays "---E" + */ +void display_int(int I, char voltmeter){ + int rem; + char N = 3, sign = 0, i; + if(I < -999 || I > 9999){ + set_display_buf("---E"); + return; + } + display_buffer[0] = ' '; + // prepare buffer for voltmeter's values + if(voltmeter){ + for(i = 1; i < 4; i++) + display_buffer[i] = ' '; + }else{ + for(i = 1; i < 4; i++) + display_buffer[i] = 0; + } + if(I == 0){ // just show zero + display_buffer[3] = 0; + return; + } + if(I < 0){ + sign = 1; + I *= -1; + } + do{ + rem = I % 10; + display_buffer[N] = rem; + I /= 10; + }while(--N > -1 && I); + if(sign && N > -1) display_buffer[N] = 16; // minus sign + if(voltmeter) display_buffer[1] |= 0x80; +} + +/** + * displays digital point at position i + * @param i - position to display DP, concequent calls can light up many DPs + */ +void display_DP_at_pos(U8 i){ + if(i > 3) return; + display_buffer[i] |= 0x80; +} diff --git a/voltmeters/src/4-digit/led.h b/voltmeters/src/4-digit/led.h new file mode 100644 index 0000000..81f52c6 --- /dev/null +++ b/voltmeters/src/4-digit/led.h @@ -0,0 +1,43 @@ +/* + * led.h + * + * Copyright 2014 Edward V. Emelianoff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#pragma once +#ifndef __LED_H__ +#define __LED_H__ + +#include "stm8l.h" + +void set_display_buf(char *str); +void show_buf_digit(U8 N); +void show_next_digit(); +void lights_off(); +void display_int(int i, char voltmeter); +void display_DP_at_pos(U8 i); + +/** + * Initialize ports + * PA1|3, PB4|5, PC3|4|5|6|7, PD1|4|6 +*/ +#define LED_init() do{ \ + PA_DDR = 0x0a; PB_DDR = 0x30; PC_DDR = 0xf8; PD_DDR = 0x52; \ + PA_CR1 = 0x0a; PB_CR1 = 0x30; PC_CR1 = 0xf8; PD_CR1 = 0x52; \ + }while(0) + +#endif // __LED_H__ diff --git a/voltmeters/src/4-digit/main.c b/voltmeters/src/4-digit/main.c new file mode 100644 index 0000000..5ea6e08 --- /dev/null +++ b/voltmeters/src/4-digit/main.c @@ -0,0 +1,152 @@ +/* + * main.c + * + * Copyright 2014 Edward V. Emelianoff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "main.h" +#include "interrupts.h" +#include "led.h" + +int temp; +#define PIX_SORT(a,b) { if ((a)>(b)) PIX_SWAP((a),(b)); } +#define PIX_SWAP(a,b) { temp=(a);(a)=(b);(b)=temp; } +int p[9]; // buffer for median filtering +int opt_med9(){ + PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ; + PIX_SORT(p[0], p[1]) ; PIX_SORT(p[3], p[4]) ; PIX_SORT(p[6], p[7]) ; + PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ; + PIX_SORT(p[0], p[3]) ; PIX_SORT(p[5], p[8]) ; PIX_SORT(p[4], p[7]) ; + PIX_SORT(p[3], p[6]) ; PIX_SORT(p[1], p[4]) ; PIX_SORT(p[2], p[5]) ; + PIX_SORT(p[4], p[7]) ; PIX_SORT(p[4], p[2]) ; PIX_SORT(p[6], p[4]) ; + PIX_SORT(p[4], p[2]) ; return(p[4]) ; +} + + +U32 Global_time = 0L; // global time in ms +//eeprom_data *saved_data = (eeprom_data*)EEPROM_START_ADDR; + +//U32 testtimer; + +// one digit emitting time +#define LED_delay 1 +/* +U8 change_eeprom_value(U8 *addr, U8 *val, U8 len){ + U8 i; + // unlock memory + FLASH_DUKR = EEPROM_KEY1; + FLASH_DUKR = EEPROM_KEY2; + // check bit DUL=1 in FLASH_IAPSR + if(!(FLASH_IAPSR & 0x08)) + return 0; + for(i = 0; i < len; i++) + *addr = val[i]; + while(!(FLASH_IAPSR & 0x04)); // wait till end + // clear DUL to lock write + FLASH_IAPSR &= ~0x08; + return 1; +} + +void eeprom_default_setup(){ + eeprom_data template = { + .magick = EEPROM_MAGICK, + .ADU_to_mV = DEFAULT_ADU_TO_MV, + .max_ADU = DEFAULT_MAX_ADU + }; + if(saved_data->magick != EEPROM_MAGICK){ + if(change_eeprom_value((U8*)saved_data, (U8*)&template, sizeof(eeprom_data))) + testtimer = saved_data->ADU_to_mV; + else + testtimer = 999; + }else{ + testtimer = 0; // other times - from zero + } +} +*/ + +int main() { + U32 T_LED = 0L; // time of last digit update + U32 T_time = 0L; // timer + int U = 0; + int pidx = 0; // index in median buffer + long voltage = 0L; + long cntr = 0; + // Configure clocking + CLK_CKDIVR = 0; // F_HSI = 16MHz, f_CPU = 16MHz + // Configure pins + CFG_GCR |= 1; // disable SWIM + LED_init(); + CCR |= 0x28; // make shure that we are on level 3 - disabled SW priority + // Configure Timer1 + // prescaler = f_{in}/f_{tim1} - 1 + // set Timer1 to 1MHz: 16/1 - 1 = 15 + TIM1_PSCRH = 0; + TIM1_PSCRL = 15; // LSB should be written last as it updates prescaler + // auto-reload each 1ms: TIM_ARR = 1000 = 0x03E8 + TIM1_ARRH = 0x03; + TIM1_ARRL = 0xE8; + // interrupts: update + TIM1_IER = TIM_IER_UIE; + // auto-reload + interrupt on overflow + enable + TIM1_CR1 = TIM_CR1_APRE | TIM_CR1_URS | TIM_CR1_CEN; + //eeprom_default_setup(); + // configure ADC + // select PD2[AIN3] & enable interrupt for EOC + ADC_CSR = 0x23; + ADC_TDRL = 0x08; // disable Schmitt triger for AIN3 + // right alignment + ADC_CR2 = 0x08; // don't forget: first read ADC_DRL! + // f_{ADC} = f/18 & continuous non-buffered conversion & wake it up + ADC_CR1 = 0x73; + ADC_CR1 = 0x73; // turn on ADC (this needs second write operation) + + // enable all interrupts + enableInterrupts(); + set_display_buf(" E0 "); // low power -> infinitive rebooting + // Loop + do { + // onse per 300ms refresh displayed value + if(((unsigned int)(Global_time - T_time) > 300) || (T_time > Global_time)){ + T_time = Global_time; + voltage /= cntr; // average + // convert ADU to U: U = 10[R2/(R5,6+R2)]*ADU>>10[norm] *100[100th of V]*3.3[amplitude] -> + // U = (3300*ADU)>>10; + voltage *= 3300; + U = (int)(voltage >> 10); + display_int(U, 1); + cntr = 0; + voltage = 0L; + pidx = 0; + } + if((U8)(Global_time - T_LED) > LED_delay){ + if(ADC_ready){ + // prepare data for rounded output + p[pidx] = ADC_value; + if(++pidx == 9){ // buffer is ready + voltage += (long)(opt_med9()); + cntr++; + pidx = 0; + } + ADC_ready = 0; + } + T_LED = Global_time; + show_next_digit(); + } + } while(1); +} + diff --git a/voltmeters/src/4-digit/main.h b/voltmeters/src/4-digit/main.h new file mode 100644 index 0000000..04f0a4b --- /dev/null +++ b/voltmeters/src/4-digit/main.h @@ -0,0 +1,40 @@ +/* + * main.h + * + * Copyright 2015 Edward V. Emelianoff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#pragma once +#ifndef __MAIN_H__ +#define __MAIN_H__ + +#include "stm8l.h" +/* +#define EEPROM_MAGICK (0x1234) +#define DEFAULT_ADU_TO_MV (35840) +#define DEFAULT_MAX_ADU (119800) + +typedef struct{ + U16 magick; + U32 ADU_to_mV; + U32 max_ADU; +}eeprom_data; +*/ +#define CONCAT(a,b) a##_##b +#define PORT(a,b) CONCAT(a,b) + +#endif // __MAIN_H__ diff --git a/voltmeters/src/4-digit/testproj.bin b/voltmeters/src/4-digit/testproj.bin new file mode 100644 index 0000000000000000000000000000000000000000..c474e25e689b5fea83480c0aade60f000316d90d GIT binary patch literal 3066 zcmYjTOKjW786I*-lafqJBCVli*)xy7g*3@VTFC8U+XaXM zg$fiXcyN?;5*Z5=1Qv?W9^yFhvbBNg+G{WMVPS9j+#b7!!pN=L0+lvRYxN(}Rw8hI z|NOsi=6}tMc^BRJ@Ge5=F1qs=#s-WhFrLELgz*UsAI2|3PQd#Wyl=tyJ&ZrV_~UEX zpWyw^F#htI?en{+9)S^kW#j9FWB0@Fx6!bz)QSk*&b?@(3wGr5kACx4G<-YP-M#bb z*Digh^Y&E6`wWfNwve!c(p#vtgGRPc(|d+SpP><8tQ_*&*X2&N^$d~rbqSPPhrjht zk=c6mDI!gP<^+^#Uq_wIH$iq`V(Cm9VP;aZQei2YIv^%ElFV^3?j4vJBa@FmLjp~a zOplI37($PlV@PFbnhvQ^(;x;=lSVS6rb)6#jXrgV#c4dGCQOZJK#du(kQyhk9@P%1 z2P6ep#E68LNg_R(>Mt|E6sjDMG*Dzi4k-$edoh4S^y^V8fSocSDfH)oKOSe^$RGL3_v3^#F<>*sOo%CDrblr<2VR2X#_mXmjE6bch8<$# z#O~*C=x^GXKJqu+_XilS%cL=RgiZGA0`=tnvPL$i*$fREai37VD*tNi} zbNfoPvwaL?w_RFZX_vn1$3gp^k3qiYKL>f;7eFrg_qwpj{Yj9DuYwc1?N;rj<*lcgGweM|Q)W5T z9d;PSV@PntE#xFzVGA+r2yVg=q4u>ZO7YkuJa%R8!7?~3XY1C*SqqgUSJ_-~peymt z=C46Q<>7+hGSvPTYI0}uS$jzaTeP#OfDBMaa)k|j>g_ffTh9osM{qNBMx~<}4sN59 zuk83}z9Y8L!YjMTSF^@kX&W@|Rqkxh9&xw7;;5@!o{9#p|Hfa-Qr*QH$Q}kM*rOmt z+X9L0oOKe`=xnQeC2N9bwY|WzvPhsO0v(nDJ9vwC>m>uqbEAz)OfOcUvULN#VD1cPpO0fwM6!L>0&z&6bXPdkC zyPz+hkm5;8@&zXeZ$BvDq9yvma1wTifAf&D0Gvd?NdV{45ht-|%l>@Rx(LR6PWH!} z);Ul=0QF|mDu8+!R3J=&dNMbn2|0zTey?lgs_r1x;6%YmX;J zpk(VA9QM4icTZb&G5q=6YJCUYXx1v|#-qmGgKw_F+XkMLc#-R{%Wv2NV7Ur4IAoWk zxJZ?!|4kR*j(=*$^Mmci2jRKgZ7lJ=z{L(N(IU3t3%o=4RfjC?(6quE_HU}>BK#QO z6_^UEA#^eVg@^T*m;%WO*P_=Djld!OZCN_12VVEONA{22D@#m?3eeQviLg_Pwgk)W zXriqx+EJ(>kHAmxcm^o0{PgEP33nr&7<#QDV6Nx$`HQGT=_JJAPCP+w_6aKVH-nb6 zQ*?5vs82XUMLo+DM|Ovt0ZS#5rb4o&OcZmN$fizhK0gQZr-S(<*eFCJHg%6JIJBtS z&UjJJIb%hA+R2b{Gfgt42@BbvO`9f3n=xY27~D~Ggg<+0*|KU1ZgPYy+8Tr)daa@^ zcuh+rLYdY}I$RnIiVnLXb-8%O5ny`CyY-G~vXqORIF%Z%;ux!{{!S#$Bv*F^+_-}^ zeijF|1t;ptPQ;ZQ*lLbKB0(;g%0|YObU3YgdU}S)wSNV#4jdRgZOX9o2H`px*@jK( znqJc-EjQKV9-|@@AMdW6pe9L`^?FIBDwG6DDF>yHHQ5H!k|k0VHcOPZU7^t>CRh@Q zngS6he*a@22}@{}D~P>G-)!s)tpC3Rdp&;{(Px01IYm zmQB)0Hch9)1#2&v*8_qL1Q7_w>2WqgXIOz28v7!6ti80o9^nCV_!K?GPSewDj?RVQ z!WO2n3Y+J+*P^L?>|LPqJ(2Lr!N!WOAPi&Ra87R7jrVoab~h~WUk8nzSe(1N2Bb