# Subversion RepositoriesProjects

Rev
/****************************************************************************
*   Project-URL: http://www.mylifesucks.de/oss/c-strom/                    *
*                                                                          *
*   This program is free software; you can redistribute it and/or modify   *
*   the Free Software Foundation; either version 2 of the License.         *
*                                                                          *
*   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.,                                        *
*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.              *
*                                                                          *
*   Thanks to:                                                             *
*   Klaus "akku" Buettner for the hardware                                 *
*   All people at http://www.rn-wissen.de especially for the i2c stuff     *
*                                                                          *
****************************************************************************/

#include <avr/io.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdlib.h>
#include <string.h>
#include "C-Strom.h"
#include "spi_union.h"
#include "i2c_slave.h"

uint8_t EEMEM ee_checkbyte1 = CHECKBYTE1;
uint8_t EEMEM ee_checkbyte2 = CHECKBYTE2;
uint16_t EEMEM ee_cal_ampere = 512;
uint8_t EEMEM ee_sensor = 50;
uint8_t EEMEM ee_prim_r1 = 47, ee_prim_r2 = 150;
uint8_t EEMEM ee_anin_r1 = 47, ee_anin_r2 = 150;
uint8_t EEMEM ee_config = 0;

volatile uint8_t CSTROM_FLAGS = 0;
volatile uint8_t CSTROM_CONFIG = 0;

// we could use ee_cal_ampere but eeprom is slow :)
volatile uint16_t cal_ampere = 512;
volatile uint8_t sensor = 50;
volatile uint8_t prim_r1 = 47, prim_r2 = 150;
volatile uint8_t anin_r1 = 47, anin_r2 = 150;
volatile int16_t ampere, volt, anin_volt, transfer_ampere;
volatile int32_t transfer_mah, mah;
volatile int16_t average_ampere = 0;
volatile uint8_t hwver = 10;
// global space for int conversion to string
char s;

// spi buffer
union SPI_buffer_t SPI_buffer;

// PD7 High
void PD7_H() {
PORTD |=  (1 << PD7);
}

// PD7 Low
void PD7_L() {
PORTD &= ~(1 << PD7);
}

void (*LED_ON)(void) = PD7_H;
void (*LED_OFF)(void) = PD7_L;

void ampere_calibrate();
void save_eeprom();
void help(uint8_t);

/*ISR(__vector_default) {
asm("nop");
}*/

/**
* decimal itoa for 10th values
*/

char *itoa_dec(int val, char* s) {
itoa(val, s, 10);
//char x = 0;
for (uint8_t i = 0; i < 9; i++) {
if (s[i] == 0 && i > 0) {
if (i == 1) {
s[i+1] = s[i-1];
s[i-1] = '0';
s[i] = '.';
s[i+2] = 0;
} else {
s[i] = s[i-1];
s[i-1] = '.';
s[i+1] = 0;
}
break;
}
}
return s;
}

/**
* init uart
*/

void uart_init() {
UBRRL = (F_CPU / (16UL * BAUD_RATE)) - 1;

// Enable receiver and transmitter; enable RX interrupt
UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE);

//asynchronous 8N1
UCSRC = (1 << URSEL) | (3 << UCSZ0);
}

/**
* send a single <character> through uart
*/

void uart_putc(unsigned char character) {
while (!(UCSRA & (1 << UDRE)));
UDR = character;
}

/**
* send a <string> throught uart
*/

void uart_puts(char *s) {
while (*s) {
uart_putc(*s);
s++;
}
}

/**
* send a <string> from pgm space throught uart
*/

void uart_puts_pgm(char *string) {
}

/**
* change the sensor type
*/

void sensor_change(uint8_t new_value) {
if (new_value < 10) new_value = 0;
else if (new_value > 250) new_value = 250;
sensor = new_value;
uart_puts_pgm(PSTR("\r\nSensor is now: "));
uart_puts(itoa(sensor, s, 10));
uart_puts("A\r\n");
}

/**
* change the r2 value
*/

void r2_change(uint8_t which, uint8_t new_value) {
if (which == V_ANIN) {
uart_puts_pgm(PSTR("\r\nANIN R2 is now: "));
anin_r2 = new_value;
uart_puts(itoa_dec(anin_r2, s));
} else {
uart_puts_pgm(PSTR("\r\nPRIMARY R2 is now: "));
prim_r2 = new_value;
uart_puts(itoa_dec(prim_r2, s));
}
uart_puts_pgm(PSTR("kOhm\r\n"));
}

/**
* enable/disable TWI
*/

void twi_change() {
uart_puts_pgm(PSTR("\r\nTWI turned "));
if (CSTROM_CONFIG & CSTROM_TWI) {
uart_puts_pgm(PSTR("ON"));
} else {
uart_puts_pgm(PSTR("OFF"));
}
}

/**
* Interrupt handler for received data through UART1
*/

SIGNAL(SIG_UART_RECV) {
unsigned char c = UDR;
switch (c) {
case 'c':
ampere_calibrate();
break;
case 's':
save_eeprom();
break;
case '+':
sensor_change(100);
break;
case '-':
sensor_change(50);
break;
case 'e':
if (hwver == 11) r2_change(V_ANIN, anin_r2 + 1);
break;
case 'd':
if (hwver == 11) r2_change(V_ANIN, anin_r2 - 1);
break;
case 'r':
r2_change(V_PRIMARY, prim_r2 + 1);
break;
case 'f':
r2_change(V_PRIMARY, prim_r2 - 1);
break;
case 'T':
CSTROM_CONFIG ^= CSTROM_TWI;
twi_change();
break;
case 'h':
help(0);
break;
default:
asm("nop"); // :-)
}
}

/**
* Interrupt handler for transmitting data through UART1
*/

SIGNAL(SIG_UART_TRANS) {
}

/**
*/

uint8_t i;
uint16_t result = 0;

// enable ADC and set clk div to 64

_delay_us(5);

// set up channel
// use internal reference

// wait for conversion to be complete

// read in three times and get the average
for(i=0; i<3; i++) {
// start conversion

// wait for conversion to be complete

}

// get average
result /= 3;

return result;
}

/**
* init SPI slave interrupt conrolled
*/

void Init_Slave_IntContr (void) {
volatile char IOReg;
// Set PB4(MISO) as output
DDRB    = (1<<PB4);
// MOSI Pullup
PORTB |= _BV(3);
// Enable SPI Interrupt and SPI in Slave Mode
SPCR  = (1<<SPIE)|(1<<SPE);
IOReg   = SPSR; // Clear SPIF bit in SPSR
IOReg   = SPDR;
SPCR |= _BV(SPIE); // duplicated
}

/**
* SPI interrupt handling
*/

ISR(SPI_STC_vect) {
LED_ON();

unsigned char foo;
foo = SPDR;
//uart_putc(foo);
switch (foo) {
case 'A': // requested ampere high bits for next transmission
CSTROM_FLAGS |= CSTROM_SPILOCKED;
foo = SPI_buffer.buffer.c;
break;
case 'B': // requested low bits
foo = SPI_buffer.buffer.c;
break;
case 'C': // wasted ampere high bits in next
foo = SPI_buffer.buffer.c;
break;
case 'D': // 2nd highest 8bits
foo = SPI_buffer.buffer.c;
break;
case 'E': // 3rd highest 8bits
foo = SPI_buffer.buffer.c;
break;
case 'F': // lowest 8bits
foo = SPI_buffer.buffer.c;
break;
case 'G': // lowest 8bits
foo = SPI_buffer.buffer.c;
break;
case 'H': // lowest 8bits
foo = SPI_buffer.buffer.c;
break;
case 'I': // challange over
foo = 'd'; // done :)
CSTROM_FLAGS &= ~CSTROM_SPILOCKED;
break;
default:  // what else? nothin now
foo = 'X';
}
// write back foo in next transmission
SPDR = foo;

//uart_putc(foo);

LED_OFF();
}

/**
* read data saved in eeprom
*/

void get_eeprom() {
uart_puts("done\r\n");
} else {
uart_puts("\tNo data found in eeprom, using default data...\r\n");
}
}

/**
* save data to eeprom
*/

void save_eeprom() {
uart_puts("\r\nSaving data to eeprom...");
eeprom_write_byte(&ee_checkbyte1, CHECKBYTE1);
eeprom_write_byte(&ee_checkbyte2, CHECKBYTE2);
eeprom_write_byte(&ee_sensor, sensor);
eeprom_write_word(&ee_cal_ampere, cal_ampere);
//if (hwver == 11)  {
// why not saving when not needed, there is space
eeprom_write_byte(&ee_anin_r1, anin_r1);
eeprom_write_byte(&ee_anin_r2, anin_r2);
//}
eeprom_write_byte(&ee_prim_r1, prim_r1);
eeprom_write_byte(&ee_prim_r2, prim_r2);
eeprom_write_byte(&ee_config, CSTROM_CONFIG);
uart_puts("done\r\n");
}

/**
* calibrate the current sensor... has to be 0A during this time!
*/

void ampere_calibrate() {
cli();
uart_puts("\r\nCalibrating...");
uint16_t temp_cal = 0;
for (uint8_t i = 0; i < 10; i++) {
uart_puts("#");
_delay_ms(100);
}
cal_ampere = temp_cal / 10;
uart_puts("done. Offset is now: ");
uart_puts(itoa(cal_ampere, s, 10));
uart_puts("\r\n");
sei();
}

volatile uint16_t timer = 0, cs = 0;
/**
* init timer0
*/

void init_timer0(void){
// set up timer
TCCR0 |= (1 << CS00) | (1 << CS01); // timer0 prescaler 64
TIMSK |= (1 << TOIE0); // enable overflow timer0
}

/**
* timer overflow handler, should be 1ms
*/

SIGNAL(SIG_OVERFLOW0) {
timer++;
// this should be 100ms
if (timer == 100) {
timer = 0;
cs++;
average_ampere += ampere;
CSTROM_FLAGS |= CSTROM_WRITEUART;
}
// this should be 1s
if (cs == 10) {
cs = 0;
mah += average_ampere / 360;
average_ampere = 0;
}
}

/**
* write <len> through uart spaces
*/

void write_space(uint8_t len) {
while (len--) {
uart_putc(' ');
}
}

/**
* check which hardware version we have here
*/

void check_hw() {
// check if pin was output and has pullup
uint8_t old_DDRD7 =  DDRD & (1 << PD7);
uint8_t old_PORTD7 =  PORTD & (1 << PD7);

// if it was, make it input
if (old_DDRD7) DDRD &= ~(1 << PD7); // PD7 input (LED)
if (!old_PORTD7) PORTD |= (1 << PD7); // PD7 enable pullup (LED)

if (PIND & (1 << PD7)) {
hwver = 11;
LED_ON = PD7_L;
LED_OFF = PD7_H;
}

// output again
if (!old_PORTD7) PORTD &= ~(1 << PD7); // PD7 disable pullup (LED)
if (old_DDRD7) DDRD |= (1 << PD7); // PD7 output (LED)
}

/**
* call for help whenever needed
*/

uart_puts_pgm(PSTR("\r\nC-STROM\r\n\tBUILD: "));
uart_puts_pgm(PSTR(BUILDDATE));
uart_puts("\r\n\tHW: ");
uart_puts(itoa_dec(hwver, s));

uart_puts("\r\n");

uart_puts_pgm(PSTR("\tSensor: "));
uart_puts(itoa(sensor, s, 10));
uart_puts_pgm(PSTR("A\tCalibration: "));
uart_puts(itoa(cal_ampere, s, 10));

uart_puts_pgm(PSTR("\r\n\tTWI is "));
if (CSTROM_CONFIG & CSTROM_TWI) {
uart_puts_pgm(PSTR("ON, SPI may not work!!!"));
} else {
uart_puts_pgm(PSTR("OFF"));
}

uart_puts_pgm(PSTR("\r\n\tPIMARY R2: "));
uart_puts(itoa_dec(prim_r2, s));
if (hwver == 11) {
uart_puts_pgm(PSTR("kOhm"));
uart_puts_pgm(PSTR("\tANIN R2: "));
uart_puts(itoa_dec(anin_r2, s));
}
uart_puts_pgm(PSTR("kOhm\r\n"));

uart_puts_pgm(PSTR("\tCommands available:\r\n"));
uart_puts_pgm(PSTR("\t\th : help on commands (this)\r\n"));
uart_puts_pgm(PSTR("\t\tc : calibrate ampere\r\n"));
uart_puts_pgm(PSTR("\t\tT : toggle TWI (may break SPI communication!)\r\n"));
uart_puts_pgm(PSTR("\t\t+/- : to change sensor\r\n"));
uart_puts_pgm(PSTR("\t\tr/f : to change PRIMARY-R2 Value\r\n"));
if (hwver == 11) {
uart_puts_pgm(PSTR("\t\te/d : to change ANIN-R2 Value\r\n"));
}
uart_puts_pgm(PSTR("\t\ts : save values\r\n"));
uart_puts_pgm(PSTR("\tnow enjoy it and have fun...\r\n\r\n"));
}

/**
* Main
*/

int main (void) {
DDRD |= (1 << PD7); // PD7 output (LED)

check_hw();
uart_init();

Init_Slave_IntContr();
init_timer0();

sei();   // Enable Global Interrupts

uart_puts("\x1B[2J\x1B[H"); // clear serial

help(1);

if (CSTROM_CONFIG & CSTROM_TWI) init_twi_slave(CSTROM_I2C);

int16_t raw_volt = 0, raw_ampere = 0, raw_aninvolt = 0;
char c = "         ";
c = 0;

//strom_data  = *((SPI_strom_data_t*) &spi_buffer);
//*spi_buffer = *((uint8_t*) (void*) &strom_data);

LED_ON();

while (1) { // Loop Forever

// we have got a normal voltage measuring circuit that takes the lipo-voltage
Uo = Ue * (R1 / (R2 + R1))
Ue = Uo * (R2 + R1) / R1
the board has got r1 = 4.7k and r2 = 15k
but since 1step is 0,0048828125V = 4,8828125mV and not 5mV there
is some conversion to do for raw_volt --**-> Uo
this should end up in 10th of volts */

raw_volt = ((uint32_t)raw_volt * (uint32_t)48828) / (uint32_t)10000;
volt = (int16_t) (((uint32_t)raw_volt * (uint32_t)(prim_r1 + prim_r2)) / (uint32_t)prim_r1) / 100;
if (volt < 0) volt = 0;

// and we have got a seccond voltage measuring circuit for user voltages
/* some conversion to do for raw_volt --**-> Uo
this should end up in 10th of volts */

raw_aninvolt = ((uint32_t)raw_aninvolt * (uint32_t)48828) / (uint32_t)10000;
anin_volt = (int16_t) (((uint32_t)raw_aninvolt * (uint32_t)(anin_r1 + anin_r2)) / (uint32_t)anin_r1) / 100;
if (anin_volt < 0) anin_volt = 0;

/* according to datasheet sensitivity is nominal 40mV per A for the 50A chip
this would mean 50A ^= 2V since 0A is set to 2.5V output Voltage we get
a range of 0.5V till 4.5V for the full range.
the atmega ADC features 0...5V range divided into 10bit ^= 1024 steps
so 0,0048828125V, or 4,8828125mV, is one step
this leads us to 0,8192 steps per 0,1A and somehow the below formula
and i know that 32bit is evil, but what else does this device has to do? :)
this should end up in 100th of ampere */

ampere = (int16_t) (((int32_t)(((int16_t)raw_ampere - (int16_t)cal_ampere)) * (int32_t)10000) / (int32_t) 819);
if (sensor == 100) ampere *= 2;

if ((CSTROM_FLAGS & CSTROM_WRITEUART)) {
uart_puts("V: ");
uart_puts(itoa_dec(volt, s));
write_space(10-strlen(s));

uart_puts("AN-IN V: ");
uart_puts(itoa_dec(anin_volt, s));
write_space(10-strlen(s));

uart_puts("A: ");
uart_puts(itoa(ampere, s, 10));
write_space(10-strlen(s));

uart_puts("C: ");
uart_puts(itoa(mah, s, 10));
write_space(10-strlen(s));

uart_puts("\r");
CSTROM_FLAGS &= ~CSTROM_WRITEUART;
}

//spi_buff
if (!(CSTROM_FLAGS & CSTROM_SPILOCKED)) {
// TESTTING
if (!(CSTROM_CONFIG & CSTROM_TWI)) CSTROM_FLAGS |= CSTROM_SPILOCKED;
SPI_buffer.data.ampere = ampere;
SPI_buffer.data.mah = mah;
if (hwver == 11) {
SPI_buffer.data.volt = anin_volt;
} else {
SPI_buffer.data.volt = volt;
}
}
}
return 0;
}
{"ft_lang_label":"__label__en","ft_lang_prob":0.535925,"math_prob":0.96550983,"size":14254,"snap":"2022-27-2022-33","text_gpt3_token_len":4909,"char_repetition_ratio":0.15929824,"word_repetition_ratio":0.068151444,"special_character_ratio":0.40500912,"punctuation_ratio":0.20200753,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9901635,"pos_list":[0],"im_url_duplicate_count":[null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2022-08-13T03:36:59Z\",\"WARC-Record-ID\":\"<urn:uuid:c4c71e48-4201-4a0e-975d-74199323f9e9>\",\"Content-Length\":\"130135\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:20c641fd-a0a0-483c-bc7c-768bdf4c6402>\",\"WARC-Concurrent-To\":\"<urn:uuid:bb19f2bc-1e65-4323-b96a-b1eeeee0da25>\",\"WARC-IP-Address\":\"89.58.9.57\",\"WARC-Target-URI\":\"https://svn.mikrokopter.de/websvn/filedetails.php?repname=Projects&path=%2FC-OSD%2FC-Strom%2Ftrunk%2FC-Strom.c&rev=771\",\"WARC-Payload-Digest\":\"sha1:KL7OV2EF7BT2URIUOWC6GM2C6ASTL5ZP\",\"WARC-Block-Digest\":\"sha1:PPZHBBP3KJXTD6IBHOH72PYPQ5272BAD\",\"WARC-Identified-Payload-Type\":\"application/xhtml+xml\",\"warc_filename\":\"/cc_download/warc_2022/CC-MAIN-2022-33/CC-MAIN-2022-33_segments_1659882571869.23_warc_CC-MAIN-20220813021048-20220813051048-00432.warc.gz\"}"}