/* ----------------------------------------------------- v003_uart.cpp Rudimentaere UART-Funktionen MCU : CH32V003 Takt : 48 MHz 30.11.2025 R. Seelig ------------------------------------------------------ */ #include "v003_uart.h" // -------------------------------------------------------------------- // V003uart (Konstruktor) // -------------------------------------------------------------------- V003uart::V003uart() { } /* -------------------------------------------------------------------- begin initialisiert serielle Schnittstelle mit Protokoll 8N1 TxD an Pin PD5, RxD an Pin PD6 Uebergabe: baudrate : einzustellende Baudrate ---------------------------------------------------------- */ void V003uart::begin(uint32_t brate) { #define pinnr 6 // PD6 baudrate= brate; // Enable UART and GPIOD RCC->APB2PCENR |= RCC_APB2Periph_GPIOD | RCC_APB2Periph_USART1; // Push-Pull, 10MHz Output on D5, alternate function (TxD) GPIOD->CFGLR = (GPIOD->CFGLR & ~(0x0f << (4*5))) | ((GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<( 4*5 )); // PD6 Pull-Up Widerstand an GPIOD->BSHR |= (1 << pinnr); // PD6 als Input GPIOD->CFGLR &= ~(0x0f << (4 * pinnr)); GPIOD->CFGLR |= ((GPIO_CNF_IN_PUPD) << (4 * pinnr)); GPIOD->BSHR |= (1 << pinnr); // Setup UART for 8n1 USART1->CTLR1 = USART_WordLength_8b | USART_Parity_No | USART_Mode_Tx | USART_Mode_Rx; USART1->CTLR2 = USART_StopBits_1; // Set baud rate and enable UART USART1->BRR = ((FUNCONF_SYSTEM_CORE_CLOCK) + (baudrate)/2) / (baudrate); USART1->CTLR1 |= CTLR1_UE_Set; } /* ---------------------------------------------------------- putchar sendet ein Zeichen auf der seriellen Schnittstelle Uebergabe: ch : zu sendendes Zeichen ---------------------------------------------------------- */ void V003uart::putchar(uint8_t ch) { while(!(USART1->STATR & USART_FLAG_TXE)); // warten bis evtl. vorangegangenes Zeichen gesendet ist USART1->DATAR = ch; } /* ---------------------------------------------------------- getchar wartet, bis auf der seriellen Schnittstelle ein Zeichen eingegangen ist und liest dieses ein. Rueckgabe: gelesenes Zeichen ---------------------------------------------------------- */ uint8_t V003uart::getchar(void) { while(!(USART1->STATR & USART_FLAG_RXNE)); return USART1->DATAR; } /* ---------------------------------------------------------- ischar testet, ob auf der seriellen Schnittstelle ein Zeichen eingegangen ist, liest dieses aber nicht ein Rueckgabe: 1 : es ist ein Zeichen eingetroffen 0 : kein Zeichen verfuegbar ---------------------------------------------------------- */ uint8_t V003uart::ischar(void) { return (USART1->STATR & USART_FLAG_RXNE); } /* ---------------------------------------------------------- prints gibt einen AsciiZ String auf dem UART aus ---------------------------------------------------------- */ void V003uart::prints(char *txbuf) { while(*txbuf) { putchar(*txbuf); txbuf++; } } /* ------------------------------------------------------------ printint gibt einen Integer dezimal aus. Ist Uebergabe "komma" != 0 wird ein "Kommapunkt" mit ausgegeben. Groesste darstellare Zahl ist 99.999.999 Bsp.: 12345 wird als 123.45 ausgegeben. (ermoeglicht Pseudofloatausgaben im Bereich) ------------------------------------------------------------ */ void V003uart::printint(int i, char komma) { typedef enum boolean { FALSE, TRUE }bool_t; static int zz[] = { 10000000, 1000000, 100000, 10000, 1000, 100, 10 }; bool_t not_first = FALSE; uint8_t zi; komma= 8-komma; if (!i) { putchar('0'); } else { if(i < 0) { putchar('-'); i = -i; } int z, b; for(zi = 0; zi < 7; zi++) { z = 0; b = 0; while(z + zz[zi] <= i) { b++; z += zz[zi]; } if(b || not_first) { putchar('0' + b); not_first = TRUE; } if (zi+1 == komma) { if (!not_first) putchar('0'); putchar('.'); not_first= TRUE; } i -= z; } putchar('0' + i); } } /* ---------------------------------------------------------- readln liest Asciizeichen in ein Char-Array ein. Es erfolgt ein Echo bei der Eingabe. Returntaste oder ein ueber- schreiten der Maximalanzahl der Zeichen beendet die Funktion Uebergabe: *txbuffer : Zeiger auf das Array, in das eingelesen werden soll. maxlen : maximale Anzahl einzulesender Zeichen ---------------------------------------------------------- */ void V003uart::readln(char *txbuffer, int maxlen) { int cx = 0; uint8_t ch; do { ch = getchar(); putchar((char)ch); if (cx < (maxlen-1)) { if ((ch=='\n')||(ch=='\r')||(cx==maxlen)) *txbuffer = 0; else *txbuffer = ch; cx++; txbuffer++; } } while ((ch != '\n') && (ch != '\r') && (cx < maxlen)); } /* ---------------------------------------------------------- readint liest einen Integerwert auf dem UART ein. Rueckgabe: eingegebener Integerwert ---------------------------------------------------------- */ int V003uart::readint(void) { char intbuf[11]; readln(intbuf,10); return atoi(intbuf); } /* -------------------------------------------------- locase konvertier alle Grossbuchstaben eines Strings in Kleinbuchstaben Uebergabe: str => konvertierter Ursprungstring -------------------------------------------------- */ void V003uart::locase(char *str) { while(*str) { if ((*str >= 'A') && (*str <= 'Z')) *str += 'a' - 'A'; str++; } } /* ---------------------------------------------------------- ahtoi uart ascii hex to integer einfache Konvertierung eines Hex-Strings zu einem Integerwert. Uebergabe: *str: Zeiger, der einen im String enthaltenen Hexadezimalwert repraesentiert *error: Zeiger der den Fehlercode aufnimmt Rueckgabe: error: 0 => kein Fehler 1 => String war kein Hexadezimalwert konvertierter Integerwert ---------------------------------------------------------- */ uint32_t V003uart::ahtoi(char *str, char *error) { char ch; uint32_t result; char puffer[10]; char *ptr; strcpy(puffer,str); locase(puffer); ptr= &puffer[0]; *error= 0; result= 0; do { ch= *ptr; if ((ch < '0') || ((ch > '9') && (ch < 'a')) || (ch > 'f') ) { *error= 1; return 0xffffffff; } if (ch< 'a') { ch -= '0'; } else { ch -= 87; } result = (result << 4) + ch; ptr++; } while (*ptr); return result; } /* ---------------------------------------------------------- readhex liest einen hexadezimalen Zahlenwert auf dem UART ein. Rueckgabe: eingegebener Integerwert ---------------------------------------------------------- */ int V003uart::readhex(void) { char intbuf[9]; char error; readln(intbuf,8); if (intbuf[0]== 0) return 0; return ahtoi(intbuf, &error); } /* ------------------------------------------------------------ hexnibbleout gibt die unteren 4 Bits eines chars als Hexaziffer aus. Eine Pruefung ob die oberen vier Bits geloescht sind erfolgt NICHT ! ------------------------------------------------------------- */ void V003uart::hexnibbleout(uint8_t b) { if (b< 10) b+= '0'; else b+= 55; putchar(b); } /* ------------------------------------------------------------ printhex gibt einen 16-Bit Integer hexadezimal aus. Ist die auszugebende Zahl >= 0xff erfolgt die Ausgabe 2-stellig, ist sie groesser erfolgt die Ausgabe 4-stellig. Ist out16 gesetzt, erfolgt Ausgabe immer 4 stellig ------------------------------------------------------------ */ void V003uart::printhex(uint16_t h, char out16) { uint8_t b; if ((h> 0xff) || out16) // 16 Bit-Wert { b= (h >> 12); hexnibbleout(b); b= (h >> 8) & 0x0f; hexnibbleout(b); } b= h; b= (h >> 4) & 0x0f; hexnibbleout(b); b= h & 0x0f; hexnibbleout(b); }