/** * @file HW_UART_ATY.c * * @param Project DEVICE_GENERAL_ATY_LIB * * @author ATY * * @copyright * - Copyright 2017 - 2026 MZ-ATY * - This code follows: * - MZ-ATY Various Contents Joint Statement - * * https://mengze.top/MZ-ATY_VCJS * - CC 4.0 BY-NC-SA - * * https://creativecommons.org/licenses/by-nc-sa/4.0/ * - Your use will be deemed to have accepted the terms of this statement. * * @brief functions of uart for C platform * * @version * - 1_01_221231 > ATY * -# Preliminary version, first Release * - 1_02_240410 > ATY * -# add multy addr and channel * -# add lock * - 1_03_251114 > ATY * -# remove _printf_ support * - 1_04_251118 > ATY * -# finish UartPrintf and test * @todo over with "\r\n" type ******************************************************************************** */ #ifndef __HW_UART_ATY_C #define __HW_UART_ATY_C #include "HW_UART_ATY.h" /******************************* For user *************************************/ /******************************************************************************/ /** * @brief uart send byte and init uart if not initialized * @param byte byte to send * @param dev * @return uint8_t */ uint8_t UartSendByte(uint8_t byte, struct HW_UART_ATY_Dev* dev){ __ATY_LOCK(dev); if(dev->uartInitFlag == 0){ dev->uartInitFlag = 1; dev->uartInit(dev->rx); } // while(dev->rxCount) // dev->rx[dev->rxCount--] = 0; dev->uartSendByte(byte); __ATY_UNLOCK(dev); return 0; } /** * @brief * * @param dev */ void UartRxClear(struct HW_UART_ATY_Dev* dev){ if(!dev->rxCount) return; while(dev->rxCount) dev->rx[dev->rxCount--] = 0; } /** * @brief uart send bytes * @param bytes bytes to send * @param len bytes to send * @param dev */ void UartSendBytes(uint8_t* bytes, uint16_t len, struct HW_UART_ATY_Dev* dev){ while(len--) UartSendByte(*bytes++, dev); } /** * @brief uart send string * @param str data to send * @param dev */ void UartSendStr(uint8_t* str, struct HW_UART_ATY_Dev* dev){ while(*str) UartSendByte(*str++, dev); } /** * @brief uart send float data in specified endian * @param dataFloat float number * @param endian * @param dev */ void UartSendFloat(float dataFloat, uint8_t endian, struct HW_UART_ATY_Dev* dev){ union result{ float temp_f; uint8_t temp_uint8[4]; }resultA, resultB; resultA.temp_f = dataFloat; if(endian == 'B'){ resultB.temp_uint8[0] = resultA.temp_uint8[3]; resultB.temp_uint8[1] = resultA.temp_uint8[2]; resultB.temp_uint8[2] = resultA.temp_uint8[1]; resultB.temp_uint8[3] = resultA.temp_uint8[0]; } else if(endian == 'L'){ resultB.temp_uint8[0] = resultA.temp_uint8[0]; resultB.temp_uint8[1] = resultA.temp_uint8[1]; resultB.temp_uint8[2] = resultA.temp_uint8[2]; resultB.temp_uint8[3] = resultA.temp_uint8[3]; } UartSendBytes(resultB.temp_uint8, 4, dev); } /** * @brief uart send float data in ASCII character type * @param dataFloat number to send, use double to get better * @param DECIMALS_NUM * @param dev * @note float and double is the same in C51 */ void UartSendFloatStr(float dataFloat, uint8_t DECIMALS_NUM, struct HW_UART_ATY_Dev* dev){ uint32_t integerPart, decimalPart; uint32_t power10 = 1; // Used to compute 10^DECIMALS_NUM uint8_t i; // Handle negative numbers if(dataFloat < 0){ UartSendByte('-', dev); dataFloat = -dataFloat; // Convert to positive } // Extract integer part integerPart = (uint32_t)dataFloat; // Compute 10^DECIMALS_NUM for(i = 0; i < DECIMALS_NUM; i++){ power10 *= 10; } // Compute decimal part (avoiding floating-point precision issues, +0.5 for rounding) decimalPart = (uint32_t)((dataFloat - integerPart) * power10 + 0.5); // Send integer part char buf[10]; // Buffer for integer part characters uint8_t index = 0; if(integerPart == 0){ buf[index++] = '0'; // Directly send "0" } else{ while(integerPart > 0){ buf[index++] = (integerPart % 10) + '0'; integerPart /= 10; } // Reverse the integer part before sending while(index > 0){ UartSendByte(buf[--index], dev); } } // Send decimal point if(DECIMALS_NUM > 0){ UartSendByte('.', dev); // Handle leading zeros in the decimal part for(i = DECIMALS_NUM - 1; i > 0; i--){ if(decimalPart < power10 / 10){ UartSendByte('0', dev); // Send leading zeros power10 /= 10; } } // Send decimal part index = 0; while(decimalPart > 0){ buf[index++] = (decimalPart % 10) + '0'; decimalPart /= 10; } while(index > 0){ UartSendByte(buf[--index], dev); } } // Append a space at the end UartSendByte(' ', dev); } /** * @brief uart receive data process * @note put at main while * @param dev */ void UartReceiveProcess(struct HW_UART_ATY_Dev* dev){ if(dev->uartInitFlag == 0){ dev->uartInitFlag = 1; dev->uartInit(dev->rx); } if(dev->rcvOverTimeOutCount > dev->rcvOverTimeOutCountNum){ dev->rcvOverTimeOutCount = 0; if(dev->rxCount != 0){ dev->rcvOverFlag = 0; dev->uartReceiveProcess_User(); while(dev->rxCount){ dev->rx[dev->rxCount--] = 0; } } } else dev->rcvOverTimeOutCount++; } // UartPrintf ------------------------------------------------------------------ void __uart_put_uint_base(struct HW_UART_ATY_Dev* dev, uint32_t v, uint32_t base, uint8_t upper){ char buf[32]; uint8_t i = 0; do{ uint32_t d = v % base; buf[i++] = (char)(d < 10 ? ('0' + d) : ((upper ? 'A' : 'a') + (d - 10))); v /= base; } while(v); while(i){ UartSendByte((uint8_t)buf[--i], dev); } } void __uart_put_int_dec(struct HW_UART_ATY_Dev* dev, int32_t v){ if(v < 0){ UartSendByte('-', dev); __uart_put_uint_base(dev, (uint32_t)(-v), 10u, 0u); } else{ __uart_put_uint_base(dev, (uint32_t)v, 10u, 0u); } } void __uart_put_float(struct HW_UART_ATY_Dev* dev, double v, int decimals){ if(decimals < 0) decimals = 6; if(v < 0){ UartSendByte('-', dev); v = -v; } uint32_t ip = (uint32_t)v; double frac = v - (double)ip; uint32_t p10 = 1; for(int i = 0; i < decimals; i++) p10 *= 10u; uint32_t dp = (uint32_t)(frac * (double)p10 + 0.5); if(dp >= p10){ dp -= p10; ip += 1u; } __uart_put_uint_base(dev, ip, 10u, 0u); if(decimals > 0){ UartSendByte('.', dev); char buf[16]; int idx = 0; for(int i = 0; i < decimals; i++){ buf[idx++] = (char)('0' + (dp % 10)); dp /= 10; } while(idx){ UartSendByte((uint8_t)buf[--idx], dev); } } } void __uart_put_sci(struct HW_UART_ATY_Dev* dev, double v, int decimals){ if(decimals < 0) decimals = 6; if(v == 0.0){ UartSendByte('0', dev); if(decimals > 0){ UartSendByte('.', dev); for(int i = 0; i < decimals; i++) UartSendByte('0', dev); } UartSendByte('e', dev); UartSendByte('+', dev); UartSendByte('0', dev); UartSendByte('0', dev); return; } if(v < 0){ UartSendByte('-', dev); v = -v; } int exp = 0; if(v >= 10.0){ while(v >= 10.0){ v /= 10.0; exp++; } } else if(v < 1.0){ while(v < 1.0){ v *= 10.0; exp--; } } uint32_t ip = (uint32_t)v; double frac = v - (double)ip; uint32_t p10 = 1; for(int i = 0; i < decimals; i++) p10 *= 10u; uint32_t dp = (uint32_t)(frac * (double)p10 + 0.5); if(dp >= p10){ dp -= p10; ip += 1u; if(ip >= 10u){ ip = 1u; exp++; } } __uart_put_uint_base(dev, ip, 10u, 0u); if(decimals > 0){ UartSendByte('.', dev); char buf[16]; int idx = 0; for(int i = 0; i < decimals; i++){ buf[idx++] = (char)('0' + (dp % 10)); dp /= 10; } while(idx){ UartSendByte((uint8_t)buf[--idx], dev); } } UartSendByte('e', dev); char sign = (exp >= 0) ? '+' : '-'; if(exp < 0) exp = -exp; UartSendByte((uint8_t)sign, dev); char eb[8]; int eidx = 0; do{ eb[eidx++] = (char)('0' + (exp % 10)); exp /= 10; } while(exp); while(eidx < 2) eb[eidx++] = '0'; while(eidx){ UartSendByte((uint8_t)eb[--eidx], dev); } } void UartPrintf(struct HW_UART_ATY_Dev* dev, ...){ va_list ap; va_start(ap, dev); const char* fmt = va_arg(ap, const char*); while(*fmt){ char c = *fmt++; if(c != '%'){ UartSendByte((uint8_t)c, dev); continue; } c = *fmt++; if(!c) break; int __aty_width = 0; int __aty_prec = -1; while(c >= '0' && c <= '9'){ __aty_width = __aty_width * 10 + (c - '0'); c = *fmt++; } if(c == '.'){ c = *fmt++; __aty_prec = 0; while(c >= '0' && c <= '9'){ __aty_prec = __aty_prec * 10 + (c - '0'); c = *fmt++; } } switch(c){ case '%': UartSendByte('%', dev); break; case 'c': { int v = va_arg(ap, int); UartSendByte((uint8_t)v, dev); break; } case 's': { const char* s = va_arg(ap, const char*); if(!s) s = "(null)"; UartSendStr((uint8_t*)s, dev); break; } case 'd': { int v = va_arg(ap, int); __uart_put_int_dec(dev, (int32_t)v); break; } case 'u': { unsigned int v = va_arg(ap, unsigned int); __uart_put_uint_base(dev, (uint32_t)v, 10u, 0u); break; } case 'x': { unsigned int v = va_arg(ap, unsigned int); __uart_put_uint_base(dev, (uint32_t)v, 16u, 0u); break; } case 'X': { unsigned int v = va_arg(ap, unsigned int); __uart_put_uint_base(dev, (uint32_t)v, 16u, 1u); break; } case 'f': case 'F': { double dv = va_arg(ap, double); __uart_put_float(dev, dv, __aty_prec); break; } case 'p': { void* pv = va_arg(ap, void*); UartSendStr((uint8_t*)"0x", dev); __uart_put_uint_base(dev, (uint32_t)pv, 16u, 0u); break; } case 'e': { double dv = va_arg(ap, double); __uart_put_sci(dev, dv, __aty_prec); break; } default: UartSendByte('%', dev); UartSendByte((uint8_t)c, dev); break; } } va_end(ap); } #ifdef UartPrintf_Test_ATY /** * @brief Comprehensive on-board test for UartPrintf, covering all format specifiers * @note Ensure the serial port is connected and the terminal is open with matching baudrate * @example Call UartPrintf_Test_All(&HW_UART_ATY_Dev_1) inside main() */ void UartPrintf_Test_All(struct HW_UART_ATY_Dev* dev){ /* 1. Basic chars and strings */ UartPrintf(dev, "=== 1. Basic chars and strings ===\r\n"); UartPrintf(dev, "char: %c, %c, %c\r\n", 'A', '0', '\n'); UartPrintf(dev, "str: %s, %s, %s\r\n", "Hello", "", "STC51"); /* 2. Integers (decimal) */ UartPrintf(dev, "=== 2. Integers (decimal) ===\r\n"); UartPrintf(dev, "int: %d, %d, %d, %d\r\n", 0, 123, -456, 2147483647); UartPrintf(dev, "uint: %u, %u, %u\r\n", 0, 65535, 4294967295UL); /* 3. Hexadecimal */ UartPrintf(dev, "=== 3. Hexadecimal ===\r\n"); UartPrintf(dev, "lowercase: %x, %x, %x\r\n", 0, 0x5F, 0xDEADBEEF); UartPrintf(dev, "uppercase: %X, %X, %X\r\n", 0, 0x5F, 0xDEADBEEF); /* 4. Floating point */ UartPrintf(dev, "=== 4. Floating point ===\r\n"); UartPrintf(dev, "default: %f, %f\r\n", 0.0, -3.1415926); UartPrintf(dev, "precision: %.2f, %.6f, %.0f\r\n", 3.1415926, 3.1415926, 3.1415926); UartPrintf(dev, "large: %f\r\n", 1e6); UartPrintf(dev, "small: %f\r\n", 1e-6); /* 5. Pointers */ UartPrintf(dev, "=== 5. Pointers ===\r\n"); void* p = (void*)0x1234; UartPrintf(dev, "ptr: %p\r\n", p); /* 6. Specials and escapes */ UartPrintf(dev, "=== 6. Special characters ===\r\n"); UartPrintf(dev, "%% %%\r\n"); UartPrintf(dev, "mixed: %d|%u|%x|%X|%c|%s|%f\r\n", -1, 255, 255, 255, 'X', "END", 2.718); /* 7. Scientific notation */ UartPrintf(dev, "=== 7. Scientific notation ===\r\n"); UartPrintf(dev, "%.2e, %.6e, %.0e\r\n", 12345.6789, 0.000012345, 12345.0); /* End marker */ UartPrintf(dev, "=== UartPrintf test completed ===\r\n"); } /** * @brief Quickly verify UartPrintf basic functions with minimal ROM/RAM usage */ void UartPrintf_Test_Quick(struct HW_UART_ATY_Dev* dev){ UartPrintf(dev, "QuickTest: %c %s %d %u %x %X %.3f %p %e\r\n", 'Q', "OK", -123, 123, 0xAB, 0xAB, 3.14, (void*)0x2025, 12345.6789); } #endif /* UartPrintf_Test_ATY */ #endif /* __HW_UART_ATY_C */ /************************************ etc *************************************/ /* init */ /* STM32 (Open uart global IT, open rx DMA(Mode Normal, Width Byte) and default DMA IT) */ // Uart ------------------------------------------------------------------------ // #include "HW_UART_ATY.h" // extern DMA_HandleTypeDef hdma_usart1_rx; // void UartReceiveProcess_User_1(void); // void UartInit_1(uint8_t* rx){ // HAL_UARTEx_ReceiveToIdle_DMA(&huart1, rx, UART_RX_MAX_LEN); // __HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT); // } // void UartSendByte_1(uint8_t byte){ // HAL_UART_Transmit(&huart1, (uint8_t*)&byte, 1, 0xFFFF); // } // struct HW_UART_ATY_Dev HW_UART_ATY_Dev_1 = { // // .rx = uartRx1, // .rx = {0}, // .rxCount = 0, // .txCount = 0, // .rcvOverTimeOutCountNum = 1, // .rcvOverTimeOutCount = 0, // .rcvOverFlag = 0, // .uartInitFlag = 0, // .uartInit = UartInit_1, // .uartSendByte = UartSendByte_1, // .uartReceiveProcess_User = UartReceiveProcess_User_1, // .lock = __ATY_UNLOCKED // }; // void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef* huart, uint16_t Size){ // if(huart == &huart1){ // HAL_UART_DMAStop(&huart1); // HW_UART_ATY_Dev_1.rcvOverTimeOutCount = 0; // HW_UART_ATY_Dev_1.rxCount = UART_RX_MAX_LEN - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx); // HW_UART_ATY_Dev_1.rcvOverFlag = 0; // HAL_UARTEx_ReceiveToIdle_DMA(&huart1, HW_UART_ATY_Dev_1.rx, UART_RX_MAX_LEN); // __HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT); // } // } /* 51 */ /* use */ // void main() // { // UartPrintf(&HW_UART_ATY_Dev_1, "\r\nHello word!\r\n",); // while (1) // { // UartReceiveProcess(&HW_UART_ATY_Dev_1); // } // } // /** // * @brief uart receive data analysis in user define self // */ // void UartReceiveProcess_User_1(void){ // if(HW_UART_ATY_Dev_1.rx[0] == 'O' // && HW_UART_ATY_Dev_1.rx[1] == 'K' // && HW_UART_ATY_Dev_1.rx[2] == '?') // printf_ATY("OK!"); // if(HW_UART_ATY_Dev_1.rx[0] == 'P' // && HW_UART_ATY_Dev_1.rx[1] == 'W' // && HW_UART_ATY_Dev_1.rx[2] == 'R' // && HW_UART_ATY_Dev_1.rx[3] == 'O' // && HW_UART_ATY_Dev_1.rx[4] == 'F' // && HW_UART_ATY_Dev_1.rx[5] == 'F' // ) // PWR_BTN_Off(&PWR_BTN_ATY_t_1); // // // echo back, both type has tested // UartSendBytes(HW_UART_ATY_Dev_1.rx, HW_UART_ATY_Dev_1.rxCount, &HW_UART_ATY_Dev_1); // UartPrintf(&HW_UART_ATY_Dev_1, "\r\n%s\r\n", HW_UART_ATY_Dev_1.rx); // // if(HW_UART_ATY_Dev_1.rxCount != 0){ // Modbus_Process(HW_UART_ATY_Dev_1.rx, HW_UART_ATY_Dev_1.rxCount, &MODBUS_S_LOW_ATY_Dev_1); // if(MODBUS_S_LOW_ATY_Dev_1.setFlag == 1){ // MODBUS_S_LOW_ATY_Dev_1.setFlag = 0; // TransMbRegsToFloat(mbG, &MODBUS_S_LOW_ATY_Dev_1); // } // // memcpy((char*)cdcStr, ((const char*)(HW_UART_ATY_Dev_3.rx)), HW_UART_ATY_Dev_3.rxCount); // // CDC_Transmit_FS(cdcStr, HW_UART_ATY_Dev_3.rxCount); // // memset(cdcStr, 0, HW_UART_ATY_Dev_3.rxCount); // // HW_UART_ATY_Dev_3.rxCount = 0; // } // } /******************************************************************************/ /******************************** End Of File *********************************/