Re: EEPROM, C++ a řetěžování operátorů
Pavel Hudeček
edizon na seznam.cz
Sobota Květen 27 22:42:57 CEST 2023
Žádná odpověď nepřišla, tak jsem zatím přetěžoval operátor << v rámci
pokusů na téma jestli by v AVR nešlo používat sériák C++ stylem cout << ...
A zdá se, že to jde a docela snadno. Výsledek sice sežral velkou část
flashky v ATtiny416, ale vzhledem k tomu, že cílem je to použít v
AVR64DD32, kde 64 je velikost flashky a 32 má blízko k ceně v Kč...
A předpokládám, že na ARMech to taky nebude problém.
Kdo chce prozkoumat, v příloze je zdroják.
Má to několik nastavení, třeba zda automaticky oddělovat čísla, nebo
jestli char má brát jako písmenko nebo číslo.
Všechny řádky v tom while jsou funkční, ale při spuštění na
ATtiny416-Xnano se všechny najednou nevejdou. Ten s floatama vyžaduje
zakomentování všech ostatních:-)
PH
Dne 26.05.2023 v 14:05 Pavel Hudeček napsal(a):
> Dobrý den všem,
>
> jsem poměrně zmlsanej používáním EEPROM v CodeVisionu. Typické
> zpracování naměřených dat vypadá cca takto:
>
> for (n=0; n<ADC_chanCnt; n++) {
> adData[n] = (float)(adc_data[n] + eCalOffs[n]) * eCalMult[n];
> }
>
> Můžou se tam ale vyskytnout i složitější výpočty, třeba po
> if(n==ADC_idxTemp).
>
> Když ale totéž chci udělat v Atmel Studiu, což je zas jinak mnohem
> lepší IDE než CodeVision, navíc je zdarma a bez komplikací po vypršení
> doby podpory k online licenci, vzniknou z toho hrůzy obsahující funkce
> jako eeprom_read_float(&eCalOffs + n), případně se třeba u int musí
> ten pointer přetypovávat, aby ho sežrala funkce eeprom_read_word a
> když jde o zápis, tak přetypovávat i vstupní hodnotu. Prostě fakt
> otravný.
>
> Tak jsem si řekl, že tohle by přece šlo napsat v C++. Udělat si na to
> nějakej class, jen to bude jednou hodně práce.
>
> Narazil jsem na problém, že nevím, jak udělat přetížení operátorů pro
> všech 8 kombinací RAM a EEPROM na vstupech a výstupu. Nějaké nápady?
>
> Druhá věc je, že určitě nejsem provní ani poslední koho něco takového
> napadlo. Má tu někdo zkušenosti s používáním nějkakého takového již
> hotového, nejlépe open source projektu?
------------- další část ---------------
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#define F_CPU (20000000UL)
#define F_CPUkor (F_CPU + ((F_CPU * (int8_t)SIGROW.OSC20ERR5V) / 1024L))
#define uartBaud(br) ((float) (F_CPUkor*64 / (16*(float)br)) + 0.5)
class clSerStream { // ==================================================================
friend clSerStream & operator<<(clSerStream & ss, unsigned char ch);
friend clSerStream & operator<<(clSerStream & ss, char ch);
friend clSerStream & operator<<(clSerStream & ss, bool b);
private:
enum {
cNumSepLen = 5,
cEndlLen = 3
};
static bool isUsed;
bool lastWasNum;
char numSeparator[cNumSepLen];
uint8_t digitsSend;
public:
char endl[cEndlLen];
bool autoSepNums;
bool charVal;
uint8_t bytesSend;
clSerStream(uint16_t bd, bool altPort) { // -----------------------------------------
if (isUsed) return;
if (altPort) PORTMUX.CTRLB|=PORTMUX_USART0_ALTERNATE_gc;
// alt: RxD - PORTA.2, TxD - PORTA.1 (xnano)
USART0_CTRLA=0; // int off, 485 off
USART0_CTRLB=USART_RXEN_bm+USART_TXEN_bm; // tx en, rx en
USART0_CTRLC=USART_CMODE_ASYNCHRONOUS_gc+USART_CHSIZE_8BIT_gc;
USART0_BAUD=uartBaud(bd);
endl[0]=10; endl[1]=13; endl[2]=0;
lastWasNum = 0;
numSeparator[0]=','; numSeparator[1]=' '; numSeparator[2]=0;
autoSepNums = false;
charVal = false;
bytesSend = 0;
}
~clSerStream() { // -----------------------------------------------------------------
USART0_CTRLB=0;
isUsed=false;
}
void putB(uint8_t c) { // -----------------------------------------------------------
while ((USART0.STATUS & USART_DREIF_bm) == 0);
USART0.TXDATAL=c;
bytesSend++;
}
uint8_t getB() { // -----------------------------------------------------------------
while(!(USART0_STATUS & USART_RXCIF_bm));
return USART0_RXDATAL;
}
void sendStr(char c[]) { // ---------------------------------------------------------
for (signed char n=0; c[n]!=0; n++) putB(c[n]);
lastWasNum = false;
}
void sendUint32(uint32_t xx) { // ---------------------------------------------------
char t[10];
signed char n;
long x;
digitsSend = 0;
if (autoSepNums && lastWasNum) sendStr(numSeparator);
if (xx==0) {putB('0'); digitsSend++; return;}
x=xx;
for (n=0; n<10 && x>0; n++) {
t[n] = x % 10 + '0';
x /= 10;
}
for (n-=1; n>=0; n--) {putB(t[n]); digitsSend++; }
lastWasNum = true;
}
void sendInt32(int32_t xx, bool disMinus=false) { // --------------------------------
if (xx<0) {
if (autoSepNums && lastWasNum) sendStr(numSeparator);
if (!disMinus) putB('-');
sendUint32(-xx);
} else sendUint32(xx);
}
void sendFloat(float f) { // --------------------------------------------------------
bool tSep = autoSepNums;
if (f <= __LONG_MAX__ || -f <= __LONG_MAX__) {
int32_t i32 = f;
sendInt32(i32);
autoSepNums = false;
putB('.');
if (digitsSend<8) {
if (f>=0.1 || f<=-0.1) {
int32_t dek=1;
for (digitsSend=8-digitsSend; digitsSend>0; digitsSend--) dek *= 10;
float ff = (f-(float)i32) * (float)dek;
sendInt32((int32_t)ff, true);
} else {
// moc male zatim nejsou
sendStr("00nic");
}
}
} else {
// velke zatim nejsou
sendStr("ABS>MAX");
}
autoSepNums = tSep;
lastWasNum = true;
}
void setNumSeparator(char * t, bool sw) { // ----------------------------------------
for (char n=0; n<cNumSepLen; n++) {
numSeparator[n]=t[n];
if (t[n]==0) break;
}
numSeparator[cNumSepLen-1] = 0;
autoSepNums = sw;
}
};
bool clSerStream::isUsed = false;
clSerStream & operator<<(clSerStream & ss, float val) { ss.sendFloat(val); return ss; }
clSerStream & operator<<(clSerStream & ss, double val) { ss.sendFloat(val); return ss; }
clSerStream & operator<<(clSerStream & ss, uint32_t val) { ss.sendUint32(val); return ss; }
clSerStream & operator<<(clSerStream & ss, int32_t val) { ss.sendInt32(val); return ss; }
clSerStream & operator<<(clSerStream & ss, uint16_t val) { ss.sendUint32(val); return ss; }
clSerStream & operator<<(clSerStream & ss, int16_t val) { ss.sendInt32(val); return ss; }
clSerStream & operator<<(clSerStream & ss, unsigned char ch) {
if (ss.charVal) ss.sendUint32((uint32_t)ch);
else {ss.putB(ch); ss.lastWasNum = false;}
return ss;
}
clSerStream & operator<<(clSerStream & ss, char ch) {
if (ss.charVal) ss.sendInt32((int32_t)ch);
else {ss.putB(ch); ss.lastWasNum = false;}
return ss;
}
clSerStream & operator<<(clSerStream & ss, char* t) { ss.sendStr(t); return ss; }
clSerStream & operator<<(clSerStream & ss, bool b) {
if (ss.autoSepNums && ss.lastWasNum) ss.sendStr(ss.numSeparator);
if (b) ss.sendStr("true");
else ss.sendStr("false");
ss.lastWasNum = true;
return ss;
}
clSerStream serOut(19200, true); // =====================================================
unsigned long long LLL = 1234567890123456789;
#define LED_bit 5 // bit s LEDkou
#define TL_bit 4 // bit s tlačítkem
#define TL_jeStisk ((PORTB.IN & (1<<TL_bit)) == 0) // podmínka právě je stisklé tlačítko
#define TL_neniStisk ((PORTB.IN & (1<<TL_bit)) != 0) // podmínka není stisklé
volatile unsigned int ms=0;
volatile char msSync=0;
void atomMs0() { // =====================================================================
__asm__("cli");
ms=0;
__asm__("sei");
}
unsigned int atomMsRead() { // ==========================================================
unsigned int p;
__asm__("cli");
p=ms;
__asm__("sei");
return p;
}
void cekej(unsigned int n) { // =========================================================
atomMs0();
while(atomMsRead()<=n) {
}
}
int main(void) {
// ----------------------------------------------------------------------------------
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0); // nedelit - bude 20 MHz
// ----------------------------------------------------------------------------------
PORTA.DIR=0b00000010; // 1 TXD out / 2 RXD PU en
PORTA.PIN2CTRL=PORT_PULLUPEN_bm; // zapnout pull-up pro aby nezapojené RXD negenerovalo data
PORTB.DIR=0b00100000; // 4 tlacitko on=0, 5 LED on=0
PORTB.PIN4CTRL=PORT_PULLUPEN_bm; // zapnout pull-up pro tlačítko
PORTB.OUTSET = 1<<LED_bit; // aby LEDka na začátku nesvítila
// ----------------------------------------------------------------------------------
TCA0_SINGLE_CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc; // použít přímo frekvenci procesoru (děleno 1)
TCA0_SINGLE_CTRLB = TCA_SINGLE_WGMODE_NORMAL_gc; // NORMAL - jen čítat
TCA0_SINGLE_PER = F_CPU / 1000UL; // perioda čítání bude tisícina F_CPU
TCA0_SINGLE_INTCTRL = TCA_SINGLE_OVF_bm; // přerušení od přetečení periody
TCA0_SINGLE_INTFLAGS = TCA_SINGLE_OVF_bm; // smazat případné předchozí visící přerušení
TCA0_SINGLE_CTRLA |= TCA_SINGLE_ENABLE_bm; // povolit čítač
// ---------------------------------------------------------------------------------
__asm__("sei");
uint32_t ui = 123456789;
long li = -123456789;
char ccc[] = " c ";
int i = 1234;
char chr = 123;
bool test1, test2;
serOut.autoSepNums = 1;
while (1) {
test1 = ui & 1;
test2 = ui & 2;
serOut.charVal = test1;
serOut.autoSepNums = test2;
serOut << test1 << test2 << serOut.endl;
//serOut << "a " << ui << " b " << 1234 << ccc << serOut.endl;
//serOut << ui << i << chr << serOut.endl;
serOut << li << -123456 << serOut.endl;
serOut << (unsigned char)' ' << '*' << serOut.endl << serOut.endl;
ui++;
//serOut << 12.3456789 << 555.7777777 << 1.111111111 << -987.654321 << 0.123456789 << 0.00333333 << serOut.endl;
cekej(1000);
}
}
ISR (TCA0_OVF_vect) { // ================================================================
ms++;
msSync=1;
TCA0_SINGLE_INTFLAGS = TCA_SINGLE_OVF_bm;
}
Další informace o konferenci Hw-list