; ************************************************************** ; * Include file with the UART command line processing * ; * (C)2005 by Gerh.Schmidt info@avr-asm-tutorial.net * ; ************************************************************** ; ; Provides the following routines for outside use ; ; Routine Uses Provides ; -------------------------------------------------------------- ; UartInit rmp Inits the UART receiver and trans- ; mitter ; UartSendChar Sends the char in rmp over the Uart ; UartSendOpenText rmp,R0,Z Sends the opening message ; UartDec5 X,rmp Displays the binary in R3:R2 in de- ; UartDec4 cimal over Uart, R0>0: display ; UartDec3 leading zeroes ; UartDec2 ; UartSendN5 X,rmp Displays the binary in R3:R2 in de- ; UartSendN4 cimal over Uart with a fixed length, ; UartSendN3 R0>0: display leading zeroes ; UartSendN2 ; UartHexB rmp Send the hex byte in rmp to the Uart ; UartHex16 rmp,R0,Z Sends 16 bytes with adress in Z over ; the Uart ; -------------------------------------------------------------- ; ; ; Init UART ; .EQU cUbrr = fClock/16/baud - 1 ; Baudrate generator constant ; UartInit: ldi rmp,HIGH(cUbrr) ; Init UART Baudrate generator out UBRRH,rmp ldi rmp,LOW(cUbrr) out UBRRL,rmp ldi rmp,(1<0 ; UartSubt: clr rmp ; result is here UartSubt1: sub R2,XL ; subtract LSB sbc R3,XH ; subtract MSB brcs UartSubt2 inc rmp rjmp UartSubt1 UartSubt2: add R2,XL ; add subractor again adc R3,XH add R0,rmp breq UartSubt3 subi rmp,-'0' ; add ASCII null rcall UartSendChar UartSubt3: ret ; ; Send a number over UART, number is in R3:R2 ; UartSendNmbr: clr R0 UartDec5: ldi XH,HIGH(10000) ldi XL,LOW(10000) rcall UartSubt UartDec4: ldi XH,HIGH(1000) ldi XL,LOW(1000) rcall UartSubt UartDec3: clr XH ldi XL,100 rcall UartSubt UartDec2: clr XH ldi XL,10 rcall UartSubt ldi rmp,'0' add rmp,R2 rjmp UartSendChar ; ; Send a fixed decimal ; UartSubN: clr rmp ; result is here UartSubN1: sub R2,XL ; subtract LSB sbc R3,XH ; subtract MSB brcs UartSubN2 inc rmp rjmp UartSubN1 UartSubN2: add R2,XL ; add subractor again adc R3,XH add R0,rmp subi rmp,-'0' ; add ASCII null tst R0 brne UartSubN3 ldi rmp,' ' UartSubN3: rjmp UartSendChar ; ; Send a number in R3:R2 with a fixed length ; UartSendN5: ldi XH,HIGH(10000) ldi XL,LOW(10000) rcall UartSubN UartSendN4: ldi XH,HIGH(1000) ldi XL,LOW(1000) rcall UartSubN UartSendN3: clr XH ldi XL,100 rcall UartSubN UartSendN2: clr XH ldi XL,10 rcall UartSubN ldi rmp,'0' add rmp,R2 rjmp UartSendChar ; ; Sends a byte in rmp in hex to Uart ; UartHexB: push rmp ; save byte swap rmp rcall UartHexN pop rmp UartHexN: andi rmp,0x0F cpi rmp,10 brcs UartHexN1 subi rmp,-7 UartHexN1: subi rmp,-'0' rjmp UartSendChar ; ; UartHex16 sends 16 Bytes in Hex starting at Z ; UartHex16: mov rmp,ZH rcall UartHexB mov rmp,ZL rcall UartHexB ldi rmp,16 mov R0,rmp UartHex16a: ldi rmp,' '; rcall UartSendChar ld rmp,Z+ rcall UartHexB dec R0 brne UartHex16a ldi rmp,cCr rcall UartSendChar ldi rmp,cLf rcall UartSendChar rjmp UartSendCursor ; ; UART return, restore RX buffer, send cursor ; UartRxRet: ldi rmp,LOW(sUartRxBs) ; Set buffer pointer to start sts sUartRxBp,rmp cbr rFlg,(1<' ; send cursor rjmp UartSendChar ; ; Skips leading blanks, = , " , and komma ; returns with Carry set and error message in Z, if end of ; input line is reached ; UartSkipLeading: lds R1,sUartRxBp ; read end of input line UartSkipLeading1: cp XL,R1 brcs UartSkipLeading2 ; not at the end ldi ZH,HIGH(2*UartTxtUnexEol) ; Error message ldi ZL,LOW(2*UartTxtUnexEol) sec ; set carry ret UartSkipLeading2: ld rmp,X+ ; read char from line cpi rmp,'=' breq UartSkipLeading1 cpi rmp,',' breq UartSkipLeading1 cpi rmp,' ' breq UartSkipLeading1 cpi rmp,'"' breq UartSkipLeading1 sbiw XL,1 clc ret ; ; Get next digit, carry if end of line, zero if end of number ; UartGetDigit: lds R1,sUartRxBp ; read end of input line cp XL,R1 brcs UartGetDigit1 ; not at the end ldi ZH,HIGH(2*UartTxtUnexEol) ; Error message ldi ZL,LOW(2*UartTxtUnexEol) sec ; set carry ret UartGetDigit1: ld rmp,X+ ; read digit cpi rmp,' ' ; end of number? breq UartGetDigitEnd cpi rmp,cCr breq UartGetDigitEnd cpi rmp,',' breq UartGetDigitEnd subi rmp,'0' ; make binary brcs UartGetDigitIll cpi rmp,10 ; too big? brcc UartGetDigitIll clc ; anything ok clz ret UartGetDigitIll: ldi ZH,HIGH(2*UartTxtNmbrErr) ; Illegal char in number ldi ZL,LOW(2*UartTxtNmbrErr) sec ; set carry for error UartGetDigitEnd: ret ; ; Get a decimal number from the received line ; UartGetDec: rcall UartSkipLeading brcs UartGetDec3 ; return with carry set for error clr R2 ; Result LSB clr R3 ; Result MSB UartGetDec1: rcall UartGetDigit ; read the next digit brcs UartGetDec3 ; return with carry set for error breq UartGetDec4 ; end of number reached mov R0,R2 ; Copy Result mov R1,R3 add R2,R2 ; Result*2 adc R3,R3 brcs UartGetDec2 ; number overflow add R2,R2 ; Result*4 adc R3,R3 brcs UartGetDec2 ; number overflow add R2,R0 ; Result*5 adc R3,R1 brcs UartGetDec2 ; number overflow add R2,R2 ; Result*10 adc R3,R3 brcs UartGetDec2 ; number overflow add R2,rmp ; add digit ldi rmp,0 adc R3,rmp brcc UartGetDec1 ; no number overflow, next char UartGetDec2: ldi ZH,HIGH(2*UartTxtNmbrOvf) ; Number overflow ldi ZL,LOW(2*UartTxtNmbrOvf) sec UartGetDec3: ; number error ret UartGetDec4: ; number is fine and complete clc ret ; ; ****************** RX line ********************** ; ; A complete UART RX line has been received, answer ; UartRxLine: ldi rmp,LOW(UartRxRet) ; Put UartRxRet to stack push rmp ldi rmp,HIGH(UartRxRet) push rmp ldi ZH,HIGH(2*UartCmds) ; point Z to command list ldi ZL,LOW(2*UartCmds) UartRxLine1: lpm ; Test end of command list mov rmp,R0 ; FF signals end of command list cpi rmp,0xFF brne UartRxLine3 UartRxLine2: ; End of command list, unknown command ldi ZH,HIGH(2*UartTxtUnkCmd) ; Send unknown command ldi ZL,LOW(2*UartTxtUnkCmd) rjmp UartSendZ UartRxLine3: ; Start comparing ldi XH,HIGH(sUartRxBs) ; point X to received line ldi XL,LOW(sUartRxBs) UartRxLine4: lds rmp,sUartRxBp ; read buffer pointer cp XL,rmp ; end of input buffer reached? brcs UartRxLine7 ; no, go on UartRxLine5: ; skip this command, go to next command lpm ; read next command char adiw ZL,1 ; point Z to next char mov rmp,R0 ; End of command text char cpi rmp,'#' ; end sign reached? brne UartRxLine5 ; no lpm ; Is the next char a blank? mov rmp,R0 cpi rmp,' ' brne UartRxLine6 adiw ZL,1 UartRxLine6: adiw ZL,7 ; jump over the rest of the command rjmp UartRxLine1 UartRxLine7: lpm ; Read char from flash mov rmp,R0 ; copy char from flash cpi rmp,'#' ; end of the command? breq UartRxLine8 ld rmp,X+ ; read next char from buffer sbr rmp,0x20 ; to small character cp rmp,R0 ; equal char? brne UartRxLine5 ; no, skip the command adiw ZL,1 ; next char rjmp UartRxLine4 ; to next char in buffer UartRxLine8: adiw ZL,1 ; blank behind #? lpm mov rmp,R0 cpi rmp,' ' brne UartRxLine9 adiw ZL,1 UartRxLine9: lds rmp,sUartRxBp ; End of buffer reached? cpc XL,rmp brcc UartRxLine2 ld rmp,X+ ; read next char from buffer cpi rmp,cCr ; End of command? brne UartRxLine10 ; with Parameter ; Command without parameters adiw ZL,5 ; Point Z to address lpm ; read LSB push R0 adiw ZL,1 ; read MSB lpm push R0 clc ; no parameter given ret ; jump to command UartRxLine10: ; Command line with parameter cpi rmp,'=' ; Parameter? brne UartRxLine5 ; No, search next command lpm ; read number of parameters tst R0 brne UartRxLine11 ; command has parameter ldi ZH,HIGH(2*UartTxtParaErr) ; Error message ldi ZL,LOW(2*UartTxtParaErr) rjmp UartSendZ UartRxLine11: ; Command line parameter rcall UartGetDec ; get the decimal number brcc UartRxLine17 ; number is fine rjmp UartSendZ ; error message UartRxLine17: adiw ZL,1 ; Read LSB min parameter lpm adiw ZL,1 cp R2,R0 ; compare lsb lpm ; Read MSB min parameter cpc R3,R0 ; compare msb brcs UartRxLine18 adiw ZL,1 ; Read LSB max parameter lpm adiw ZL,1 sec ; Set carry for Max+1 cpc R2,R0 ; compare lsb lpm ; Read MSB max parameter cpc R3,R0 ; compare msb brcs UartRxLine19 ; number is fine UartRxLine18: ; number out of range ldi ZH,HIGH(2*UartTxtNmbrOor) ldi ZL,LOW(2*UartTxtNmbrOor) rjmp UartSendZ UartRxLine19: ; Read adress and jump adiw ZL,1 ; read LSB lpm push R0 ; LSB on stack adiw ZL,1 ; read MSB lpm push R0 ; MSB on stack sec ; set carry, parameter ret ; jump to command adress ; ; ***************** Commands ********************************* ; ; Uart command HELP ; UartHelp: ldi ZH,HIGH(2*UartTxtHelp) ; Help message ldi ZL,LOW(2*UartTxtHelp) rjmp UartSendZ ; ; Uart command RESTART ; UartRestart: pop rmp ; destroy return adress pop rmp jmp 0 ; start new ; ; Uart command Channel ; UartChannel: brcc UartChannel1 dec R2 sts sUartCurCh,R2 UartChannel1: ; Output channel number ldi ZH,HIGH(2*UartTxtCurrCh) ldi ZL,LOW(2*UartTxtCurrCh) rcall UartSendZ lds rmp,sUartCurCh ; read current channel subi rmp,-'1' ; add ASCII-one rcall UartSendChar adiw ZL,1 ; complete output rjmp UartSendZ ; ; Gets the akku Id adress of the current channel ; UartGetAkkuId: ldi ZH,HIGH(sAdcAI1) ; Z to akku id 1 ldi ZL,LOW(sAdcAI1) lds rmp,sUartCurCh add ZL,rmp add ZL,rmp ret ; ; Set the akku id of the current channel ; UartAkkuId: brcc UartAkkuId1 rcall UartGetAkkuId st Z,R2 lds R0,sUartCurCh rcall IdSetPar UartAkkuId1: ldi ZH,HIGH(2*UartTxtAkkuId) ldi ZL,LOW(2*UartTxtAkkuId) rcall UartSendZ rcall UartGetAkkuId ld R2,Z clr R3 clr R0 rcall UartDec2 ldi rmp,cCr rcall UartSendChar ldi rmp,cLf rcall UartSendChar rjmp UartOutSettings ; ; Point rmp to current unload bit ; UartUnloadBit: lds R0,sUartCurCh ldi rmp,0x10 UartUnloadBit1: tst R0 breq UartUnloadBit2 lsl rmp dec R0 rjmp UartUnloadBit1 UartUnloadBit2: ; ; Point X to Pwm-Channel pwm register ; UartChannX: clr XH ; Point to channel pwm value ldi XL,cPwm1S lds R0,sUartCurCh ; add current channel add XL,R0 ret ; ; Get the Uart current parameter adress in X ; UartGetChPar: lds R1,sUartCurCh ; read channel lsl R1 lsl R1 lsl R1 ldi XH,HIGH(sCh1UV) ; Base address ldi XL,LOW(sCh1UV) add XL,R1 brcc UartGetChPar1 inc XH UartGetChPar1: ret ; ; Get adress of channel activity text in Z ; UartGetChAct: ldi ZH,HIGH(2*UartTxtAct) ldi ZL,LOW(2*UartTxtAct) lds R1,sUartCurCh ; current channel lds rmp,sState ; get channel states UartGetChAct1: tst R1 breq UartGetChAct2 lsr rmp lsr rmp dec R1 rjmp UartGetChAct1 UartGetChAct2: andi rmp,0x03 ; isolate bits breq UartGetChAct4 UartGetChAct3: lpm adiw ZL,1 tst R0 brne UartGetChAct3 dec rmp rjmp UartGetChAct2 UartGetChAct4: ret ; ; Set the unload threshhold voltage ; UartSetU: brcc UartSetU1 rcall UartGetChPar ; get address in X st X+,R2 ; store parameter there st X,R3 UartSetU1: rjmp UartOutSettings ; ; Set the load current on that channel ; UartSetI: brcc UartSetI1 rcall UartGetChPar ; get address in X adiw XL,2 ; load current is the second par st X+,R2 ; store the received number there st X,R3 UartSetI1: rjmp UartOutSettings ; ; Set the total work to be loaded ; UartSetW: brcc UartSetW1 ; no parameter given rcall UartGetChPar ; get address in X adiw XL,4 ; work is the third par st X+,R2 ; store the received number there st X,R3 UartSetW1: rjmp UartOutSettings ; ; Set the maintain current ; UartSetM: brcc UartSetM1 rcall UartGetChPar ; get address in X adiw XL,6 ; the fourth variable st X+,R2 ; store the parameter st X,R3 UartSetM1: rjmp UartOutSettings ; ; Set the state activity bits to the value in rmp ; input: rmp, bit 1 and 0 = activity flags ; UartSetState: lds R0,sUartCurCh ; load channel to R0 lds R2,sState ; load state bits to R2 mov R3,rmp ; save OR mask in R3 ldi rmp,0xFC ; prepare the mask for AND mov R1,rmp mov rmp,R3 ; restore original UartSetState1: tst R0 ; channel reached breq UartSetState2 sec ; next channel rol R1 sec rol R1 lsl rmp ; shift activity bits two left lsl rmp lsr R2 ; shift state bits two right lsr R2 dec R0 rjmp UartSetState1 UartSetState2: lds R0,sState and R0,R1 ; clear the two bits or R0,rmp ; set the activity bits sts sState,R0 mov rmp,R2 ; check the previous state andi rmp,0x03 ; isolate state bits cp rmp,R3 ; was the state changed? breq UartSetState4 ; no, skip the correction lds R0,sUartCurCh ; R0 is current channel cpi rmp,0x02 ; previous state was load? brne UartSetState3 ; inactive, unload or maintain call EpStore ; save loaded capacity to EEPROM sec UartSetState3: ; clear accumulated capacity, if inactive or unload call ClearCap ; clear capacity of channel in R0 UartSetState4: rjmp UartOutSettings ; ; Set activity bits in channel status clear ; UartClear: ldi rmp,0x00 rjmp UartSetState ; ; Set the unload bit and clear channel pwm ; UartUnload: rcall UartUnloadBit or rPwmOut,rmp clr rmp st X,rmp ldi ZH,HIGH(2*UartTxtUnload) ldi ZL,LOW(2*UartTxtUnload) rcall UartSendZ ldi rmp,0x01 ; Unload flags rjmp UartSetState ; ; Set activity bits in channel status to maintaining ; UartMaint: ldi rmp,0x03 rjmp UartSetState ; ; Start loading on the actual channel ; UartLoad: ldi rmp,0x02 rjmp UartSetState ; ; Write the settings in a channel ; UartOutSettings: ldi rmp,4 ; R4 is counter mov R4,rmp ldi ZH,HIGH(2*UartTxtSettings) ldi ZL,LOW(2*UartTxtSettings) rcall UartSendZ lds R1,sUartCurCh ldi rmp,'1' add rmp,R1 rcall UartSendChar rcall UartSendZ ldi XH,HIGH(sAdcAI1) ; write id ldi XL,LOW(sAdcAI1) lds rmp,sUartCurCh add XL,rmp add XL,rmp ld R2,X clr R3 rcall UartSendNmbr rcall UartSendZ push ZH push ZL rcall UartGetChAct rcall UartSendZ pop ZL pop ZH rcall UartSendZ rcall UartGetChPar UartOutSettings1: ld R2,X+ ld R3,X+ push XH push XL rcall UartSendNmbr rcall UartSendZ pop XL pop XH dec R4 brne UartOutSettings1 ret ; ; Text for the settings ; UartTxtSettings: .DB "Ch ",0 .DB ": Id=",0 .DB ", status=",0 .DB ", U= ",0 .DB "mV, I= ",0 .DB "mA, C= ",0 .DB "mAh, Im= ",0 .DB "mA",$0D,$0A,0,0 ; ; Activity status of the channel ; UartTxtAct: .DB "not connected",0 .DB "unloading",0 .DB "loading",0 .DB "maintaining",0 ; ; Switch monitor on ; UartMoniOn: ldi rmp,1<, no param: this list.",$0D,$0A .DB " or , param x (1..4): read/set akku channel number. ",$0D,$0A .DB " or , param x (1..32): read/select akku id. ",$0D,$0A .DB " or , param x (700..1200): read/set akku unload voltage.",$0D,$0A .DB " or , param x (5..175): read/set load current in mA.",$0D,$0A .DB " or , param x (10..9999): read/set capacity in mAh. ",$0D,$0A .DB " or , param x (5..100): read/set maintain current in mA ",$0D,$0A .DB ", no param: set the channel off. ",$0D,$0A .DB ", no param: switches unload output on.",$0D,$0A .DB ", no param: start loading.",$0D,$0A .DB ", no param: switches to maintaining current.",$0D,$0A .DB ", no param: switches monitoring on.",$0D,$0A .DB " or , param x (0..255): set pwm value.",$0D,$0A .DB " creates new accu id,",$0D,$0A .DB " capacity 100..9000, size 0..3, loads 0..65535, text free.",$0D,$0A .DB ", no param: list all stored accu id's.",$0D,$0A .DB ", no param: restart the controller. ",$0D,$0A,$00 ; UartTxtOpening: .DB $0D,$0A,$0D,$0A,"Akkuloader (C)2005 by info@avr-asm-tutorial.net ",$0D,$0A .DB "----------------------------------------------- ",$0D,$0A .DB "Stored accu id's : ",$00 .DB "Type 'help' for menue. ",$0D,$0A ; UartTxtUnkCmd: .DB "Unknown command! ",$0D,$0A,$00 ; UartTxtParaErr: .DB "Command has no parameters! ",$0D,$0A,$00 ; UartTxtUnexEol: .DB "Unexpected end of line!",$0D,$0A,$00 ; UartTxtNmbrErr: .DB "Illegal character in number! ",$0D,$0A,$00 ; UartTxtNmbrOvf: .DB "Number overflow! ",$0D,$0A,$00 ; UartTxtNmbrOor: .DB "Number out of range! ",$0D,$0A,$00 ; UartTxtCurrCh: .DB "Current akku channel is : ",$00,$20 .DB " ",$0D,$0A,$00 ; UartTxtPwm: .DB "Current pwm value is : ",$00 .DB " ",$0D,$0A,$00 ; UartTxtUnload: .DB "Unload bit has been set. ",$0D,$0A,$00 ; UartTxtMoniOff: .DB "Monitoring is off. ",$0D,$0A,$00 ; UartTxtMoniOn: .DB "Monitoring is on.",$0D,$0A,$00 ; UartTxtList: .DB "Id Sz Capac Loads _Rest Text____",$0D,$0A,$00,$00 ; UartTxtAkkuId: .DB "Current id is ",$00,$00 ; UartTxtNewParamErr: .DB "Missing all parameters!",$0D,$0A,$00 ; UartTxtNewSize: .DB "Illegal size!",$0D,$0A,$00 ; UartTxtNewMany: .DB "Too many id's!",$0D,$0A,$00,$00 ;