/**
* @file HW_UART_ATY.c
*
* @param Project DEVICE_GENERAL_ATY_LIB
*
* @author ATY
*
* @copyright
* - Copyright 2017 - 2025 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 Familiar functions of uart for STC51
*
* @version
* - 1_01_221231 > ATY
* -# Preliminary version, first Release
* - 1_02_240410 > ATY
* -# add multy addr and channel
* -# add lock
* - Undone: over with "\r\n" type
* - todo: printf in multi platform
********************************************************************************
*/
#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++;
}
/******************************* For user *************************************/
#if defined (__STC51_ATY)
#define BRT (uint32_t)(65536 - (uint32_t)FOSC / BAUD_RATE / 4)
// #define FOSC 5529600UL // 5.5296MHz MCU frequency
#define FOSC 24000000UL // 24MHz MCU frequency
#define BAUD_RATE 115200
/**
* @brief uart hardware init
* @note put at main init
*/
void UartInit(void)
{
SCON = 0x50; // 8bit data, variable baud rate
AUXR |= 0x40; // timer clk 1T mode
AUXR &= 0xFE; // user timer 1 as uart1 baud generate
TMOD &= 0x0F; // set timer mode
TL1 = BRT; // set timer origin value
TH1 = BRT >> 8; // set timer origin value
ET1 = 0; // disable timer IT
TR1 = 1; // start timer 1
// TI = 1;
uartMsgStruct_t.rxCount = 0x00;
uartMsgStruct_t.txCount = 0x00;
uartMsgStruct_t.busyFlag = 0;
ES = 1; // UART interrupt enable
EA = 1; // Global interrupt enable
}
/**
* @brief uart IT callback function
*/
void UartIsr(void) INTERRUPT(4)
{
if(TI)
{
TI = 0;
uartMsgStruct_t.busyFlag = 0;
}
if(RI)
{
RI = 0;
if(uartMsgStruct_t.rxCount < UART_RX_MAX_LEN)
{
uartMsgStruct_t.overCount = 0;
uartMsgStruct_t.rx[uartMsgStruct_t.rxCount++] = SBUF;
}
}
}
/**
* @brief uart send byte
* @param byte byte to send
*/
void UartSendByte(uint8_t byte)
{
uint8_t errCount = 0;
while(uartMsgStruct_t.busyFlag == 1)
{
errCount++;
if(errCount > 200)
break;
}
uartMsgStruct_t.busyFlag = 1;
SBUF = byte;
}
#elif defined(__STM32_HAL_ATY)
#include "usart.h"
#ifndef __MICROLIB
// for standart lib(not use MicroLIB)
#pragma import(__use_no_semihosting)
// define _sys_exit to avoid semi-host mode
void _sys_exit(int x)
{
x = x;
}
struct __FILE
{
int handle;
};
FILE __stdout;
#endif /* __MICROLIB */
/* In gcc, using printf() output, if there is no "\n" in output data, no data
will be printed on the screen until "\n" is encountered or the buffer overflows
Another way to refresh the output data is to run "fflush(stdout)" after
sending the data to force a refresh of the output stream
*/
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#define GETCHAR_PROTOTYPE int __io_getchar(void)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#define GETCHAR_PROTOTYPE int fgetc(FILE *f)
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE \
{
#ifdef LL
// LL_USART_TransmitData8(PRINTF_UART, ch);
// while(!LL_USART_IsActiveFlag_TC(PRINTF_UART)){}
#else
// HAL_UART_Transmit(&PRINTF_UART, (uint8_t*)&ch, 1, 0xFFFF);
#endif
return ch;
}
GETCHAR_PROTOTYPE \
{
uint8_t ch = 0;
// HAL_UART_Receive(&PRINTF_UART, &ch, 1, 0xFFFF);
return ch;
}
#endif /* PLATFORM */
/******************************************************************************/
#endif /* __HW_UART_ATY_C */
/************************************ etc *************************************/
/* init */
/* STM32 (Open uart global IT, open rx DMA(Mode Normal, Width Byte) and default DMA IT) */
// // uart2
// extern DMA_HandleTypeDef hdma_usart2_rx;
// void UartReceiveProcess_User_2(void);
// void UartInit_2(uint8_t* rx)
// {
// // __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
// HAL_UARTEx_ReceiveToIdle_DMA(&huart2, rx, UART_RX_MAX_LEN);
// __HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT);
// }
// void UartSendByte_2(uint8_t byte)
// {
// // LL
// // LL_USART_TransmitData8(huart2, byte);
// // while(!LL_USART_IsActiveFlag_TC(huart2)){}
// // HAL
// HAL_UART_Transmit(&huart2, (uint8_t*)&byte, 1, 0xFFFF);
// }
// struct HW_UART_ATY_Dev HW_UART_ATY_Dev_2 = {
// // .rx = uartRx1,
// .rx = {0},
// .rxCount = 0,
// .txCount = 0,
// .rcvOverTimeOutCountNum = 2000,
// .rcvOverTimeOutCount = 0,
// .rcvOverFlag = 0,
// .uartInitFlag = 0,
// .uartInit = UartInit_2,
// .uartSendByte = UartSendByte_2,
// .uartReceiveProcess_User = UartReceiveProcess_User_2,
// .lock = _ATY_UNLOCKED,
// .debugEnable = 0,
// // .LOG = printf
// };
// // uart3
// extern DMA_HandleTypeDef hdma_usart3_rx;
// void UartReceiveProcess_User_3(void);
// void UartInit_3(uint8_t* rx)
// {
// // __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
// HAL_UARTEx_ReceiveToIdle_DMA(&huart3, rx, UART_RX_MAX_LEN);
// __HAL_DMA_DISABLE_IT(&hdma_usart3_rx, DMA_IT_HT);
// }
// void UartSendByte_3(uint8_t byte)
// {
// // LL
// // LL_USART_TransmitData8(huart3, byte);
// // while(!LL_USART_IsActiveFlag_TC(huart3)){}
// // HAL
// HAL_UART_Transmit(&huart3, (uint8_t*)&byte, 1, 0xFFFF);
// }
// struct HW_UART_ATY_Dev HW_UART_ATY_Dev_3 = {
// // .rx = uartRx1,
// .rx = {0},
// .rxCount = 0,
// .txCount = 0,
// .rcvOverTimeOutCountNum = 2000,
// .rcvOverTimeOutCount = 0,
// .rcvOverFlag = 0,
// .uartInitFlag = 0,
// .uartInit = UartInit_3,
// .uartSendByte = UartSendByte_3,
// .uartReceiveProcess_User = UartReceiveProcess_User_3,
// .lock = _ATY_UNLOCKED,
// .debugEnable = 0,
// // .LOG = printf
// };
// void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef* huart, uint16_t Size)
// {
// if(huart == &huart2){
// HAL_UART_DMAStop(&huart2);
// HW_UART_ATY_Dev_2.rcvOverTimeOutCount = 0;
// HW_UART_ATY_Dev_2.rxCount = UART_RX_MAX_LEN - __HAL_DMA_GET_COUNTER(&hdma_usart2_rx);
// HW_UART_ATY_Dev_2.rcvOverFlag = 0;
// HAL_UARTEx_ReceiveToIdle_DMA(&huart2, HW_UART_ATY_Dev_2.rx, UART_RX_MAX_LEN);
// __HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT);
// }
// else if(huart == &huart3){
// HAL_UART_DMAStop(&huart3);
// HW_UART_ATY_Dev_3.rcvOverTimeOutCount = 0;
// HW_UART_ATY_Dev_3.rxCount = UART_RX_MAX_LEN - __HAL_DMA_GET_COUNTER(&hdma_usart3_rx);
// HW_UART_ATY_Dev_3.rcvOverFlag = 0;
// HAL_UARTEx_ReceiveToIdle_DMA(&huart3, HW_UART_ATY_Dev_3.rx, UART_RX_MAX_LEN);
// __HAL_DMA_DISABLE_IT(&hdma_usart3_rx, DMA_IT_HT);
// }
// /* if process is not too long, process function can be used at this call back;
// otherwise put process at other cycle like while or timer cycle */
// // UartReceiveProcess_User_2();
// // UartReceiveProcess_User_3();
// }
/* 51 */
/* use */
// void main()
// {
// UartSendStr("Hello word!", &HW_UART_ATY_Dev_2);
// UartSendStr("Hello word!", &HW_UART_ATY_Dev_3);
// while (1)
// {
// UartReceiveProcess(&HW_UART_ATY_Dev_2);
// UartReceiveProcess(&HW_UART_ATY_Dev_3);
// }
// }
// /**
// * @brief uart receive data analysis in user define self
// */
// void UartReceiveProcess_User_2(void)
// {
// if((HW_UART_ATY_Dev_2.rx[0] == 'O'
// && HW_UART_ATY_Dev_2.rx[1] == 'K'
// && HW_UART_ATY_Dev_2.rx[2] == '?'))
// UartSendStr("OK!", &HW_UART_ATY_Dev_2);
// }
// void UartReceiveProcess_User_3(void)
// {
// if((HW_UART_ATY_Dev_3.rx[0] == 'O'
// && HW_UART_ATY_Dev_3.rx[1] == 'K'
// && HW_UART_ATY_Dev_3.rx[2] == '?'))
// UartSendStr("OK!", &HW_UART_ATY_Dev_3);
//
// Modbus_Process(HW_UART_ATY_Dev_3.rx, HW_UART_ATY_Dev_3.rxCount, &MODBUS_S_LOW_ATY_Dev_1);
//
//
// // UartSendStr(HW_UART_ATY_Dev_1.rx, &HW_UART_ATY_Dev_3);
// if(memcmp("DSTART", (char*)HW_UART_ATY_Dev_1.rx, strlen("DSTART")) == 0)
// {
// printf("\r\nDebug START!");
// }
// else if(memcmp("temp", (char*)HW_UART_ATY_Dev_1.rx, strlen("temp")) == 0)
// {
// printf("\r\ntemp %c%c%c",
// HW_UART_ATY_Dev_1.rx[strlen("temp_")],
// HW_UART_ATY_Dev_1.rx[strlen("temp_") + 1],
// HW_UART_ATY_Dev_1.rx[strlen("temp_") + 2]);
// }
// }
/******************************************************************************/
/******************************** End Of File *********************************/