diff --git a/User/driver/ch438q.c b/User/driver/ch438q.c index fa7f255..d08a088 100644 --- a/User/driver/ch438q.c +++ b/User/driver/ch438q.c @@ -1,6 +1,8 @@ #include "ch438q.h" #include "fsmc.h" +#define CH438_CLK 1843200 /* CH438的内部时钟频率,默认外部晶振的12分频 */ + const uint8_t offsetadd[] = { 0x00, 0x10, @@ -22,12 +24,74 @@ const uint8_t Interruptnum[] = { 0x80, }; /* SSR寄存器中断号对应值 */ +static void ch438_tranconfig(uint8_t uart_num); +static void ch438_set_baudrate(uint8_t uart_num, uint32_t baudrate); + +/** + * @brief 配置串口通信参数 + * + * 设置串口通讯的格式,8个数据位,1个停止位,1个校验位,奇校验,并设置FIFO模式,触发点为112个字节。 + * + * @param uart_num 串口编号 + */ +void ch438_tranconfig(uint8_t uart_num) +{ + // 设置串口通讯的格式,8个数据位,1个停止位,1个校验位,奇校验 + ch438_write_reg(offsetadd[uart_num] | REG_LCR_ADDR, BIT_LCR_PAREN | BIT_LCR_WORDSZ1 | BIT_LCR_WORDSZ0, 1); + /* 设置FIFO模式,触发点为112个字节 */ + ch438_write_reg(offsetadd[uart_num] | REG_FCR_ADDR, BIT_FCR_RECVTG0 | BIT_FCR_RECVTG1 | BIT_FCR_FIFOEN, 1); +} + +/** + * @brief 设置CH438 UART的波特率 + * + * 通过修改CH438 UART的波特率寄存器来设置指定UART的波特率。 + * + * @param uart_num UART编号 + * @param baudrate 需要设置的波特率 + */ +static void ch438_set_baudrate(uint8_t uart_num, uint32_t baudrate) +{ + uint8_t dlab = 0; + uint16_t bandspeed; + + dlab = ch438_read_reg(offsetadd[uart_num] | REG_LCR_ADDR, 1); + dlab |= 0x80; // 置LCR寄存器的DLAB位为1 + ch438_write_reg(offsetadd[uart_num] | REG_LCR_ADDR, dlab, 1); + + bandspeed = CH438_CLK / 16 / baudrate; + ch438_write_reg(offsetadd[uart_num] | REG_DLL_ADDR, (uint8_t)bandspeed, 1); + ch438_write_reg(offsetadd[uart_num] | REG_DLM_ADDR, (uint8_t)(bandspeed >> 8), 1); + + dlab &= 0x7F; // 置LCR寄存器的DLAB位为0 + ch438_write_reg(offsetadd[uart_num] | REG_LCR_ADDR, dlab, 1); +} + +/** + * @brief 向CH438寄存器写入数据 + * + * 该函数用于向CH438芯片的指定寄存器写入指定大小的数据。 + * + * @param addr 要写入的寄存器地址 + * @param data 要写入的数据 + * @param size 要写入的数据大小(以字节为单位) + */ void ch438_write_reg(uint8_t addr, uint8_t data, uint8_t size) { uint32_t *address = (uint32_t *)(0x60000000 + addr); HAL_SRAM_Write_8b(&hsram1, address, &data, size); } +/** + * @brief 从CH438的寄存器中读取数据 + * + * 从指定的地址读取指定大小的数据。 + * + * @param addr 寄存器地址 + * @param size 要读取的数据大小(以字节为单位) + * + * @return 读取到的数据 + */ uint8_t ch438_read_reg(uint8_t addr, uint8_t size) { uint8_t data = 0; @@ -48,3 +112,114 @@ void ch438_test(void) reg_data[3] = ch438_read_reg(offsetadd[0] | REG_IIR_ADDR, 1); reg_data[4] = ch438_read_reg(offsetadd[0] | REG_LSR_ADDR, 1); } + +/** + * @brief 重置所有UART + * + * 该函数用于重置所有UART设备。 + * + * @return 无 + */ +void ch438_reset_all_uart(void) +{ + for (uint8_t i = 0; i < 8; i++) + { + ch438_write_reg(offsetadd[CH438_UART0 + i] | REG_IER_ADDR, BIT_IER_RESET, 1); + } +} + +/** + * @brief 关闭指定UART的电源 + * + * 关闭指定UART的电源,使UART进入低功耗模式。 + * + * @param uart_num UART编号,取值范围为0到3 + */ +void ch438_close_uart(uint8_t uart_num) +{ + ch438_write_reg(offsetadd[uart_num] | REG_IER_ADDR, BIT_IER_LOWPOWER, 1); +} + +/** + * @brief 关闭所有UART串口 + * + * 关闭CH438芯片上的所有UART串口。 + * + * 具体操作是向CH438的IER寄存器(中断使能寄存器)写入特定值, + * 将SLP(休眠模式使能位)和LOWPOWER(低功耗模式使能位)同时设置为1, + * 以关闭时钟振荡器并使所有UART串口进入休眠状态。 + */ +void ch438_close_all_uart(void) +{ + + ch438_write_reg(offsetadd[CH438_UART0] | REG_IER_ADDR, BIT_IER_LOWPOWER | BIT_IER_SLP, 1); // 数据手册描述:SLP和LOWPOWER同时为1,关闭时钟振荡器,所有串口进入休眠 +} + +/** + * @brief 初始化UART通信 + * + * 该函数用于初始化指定的UART端口,并设置其波特率。 + * + * @param uart_num UART端口号 + * @param baudrate 波特率 + */ +void ch438_init_uart(uint8_t uart_num, uint32_t baudrate) +{ + ch438_tranconfig(uart_num); + ch438_set_baudrate(uart_num, baudrate); +} + +/** + * @brief 检查并返回中断标识寄存器(IIR)的值 + * + * 该函数通过UART编号读取并返回中断标识寄存器(IIR)的值。 + * + * @param uart_num UART编号,用于指定要读取的UART接口 + * + * @return 返回中断标识寄存器(IIR)的值 + */ +uint8_t ch438_check_iir_reg(uint8_t uart_num) +{ + return ch438_read_reg(offsetadd[uart_num] | REG_IIR_ADDR, 1); +} + +/** + * @brief 初始化CH438的配置 + * + * 该函数用于初始化CH438芯片的配置,包括中断使能寄存器和调制解调器控制寄存器的设置。 + * + * @param uart_num UART编号,用于指定要初始化的UART通道 + */ +void ch438_init_config(uint8_t uart_num) +{ + /* CH438打开BIT_IER_IETHRE会产生一个发送空中断 */ + ch438_write_reg(offsetadd[uart_num] | REG_IER_ADDR, BIT_IER_IELINES | BIT_IER_IETHRE | BIT_IER_IERECV, 1); + ch438_check_iir_reg(uart_num); + ch438_write_reg(offsetadd[uart_num] | REG_MCR_ADDR, BIT_MCR_OUT2, 1); +} + +void ch438_send_data(uint8_t uart_num, uint8_t *data, uint16_t len) +{ + ch438_write_reg(offsetadd[uart_num] | REG_THR_ADDR, data[0], len); +} + +uint8_t ch438_recv_data(uint8_t uart_num, uint8_t *data) +{ + uint8_t data_len = 0; + uint8_t *receive_data; + receive_data = data; + while ((ch438_read_reg(offsetadd[uart_num] | REG_LSR_ADDR, 1) & BIT_LSR_DATARDY) == 0) + ; // 等待数据准备好 + while ((ch438_read_reg(offsetadd[uart_num] | REG_LSR_ADDR, 1) & BIT_LSR_DATARDY)) + { + *receive_data = ch438_read_reg(offsetadd[uart_num] | REG_RBR_ADDR, 1); + receive_data++; + data_len++; + if (data_len == 112) + { + break; + } + } + return data_len; +} + diff --git a/User/driver/ch438q.h b/User/driver/ch438q.h index 764039c..9a2ae93 100644 --- a/User/driver/ch438q.h +++ b/User/driver/ch438q.h @@ -109,8 +109,27 @@ #define CH438_IIR_FIFOS_ENABLED 0xC0 /* 起用FIFO */ +typedef enum +{ + CH438_UART0 = 0, + CH438_UART1, + CH438_UART2, + CH438_UART3, + CH438_UART4, + CH438_UART5, + CH438_UART6, + CH438_UART7, +} ch438_uart_e; + void ch438_write_reg(uint8_t addr, uint8_t data, uint8_t size); uint8_t ch438_read_reg(uint8_t addr, uint8_t size); void ch438_test(void); - +void ch438_reset_all_uart(void); +void ch438_close_uart(uint8_t uart_num); +void ch438_close_all_uart(void); +void ch438_init_uart(uint8_t uart_num, uint32_t baudrate); +uint8_t ch438_check_iir_reg(uint8_t uart_num); +void ch438_init_config(uint8_t uart_num); +void ch438_send_data(uint8_t uart_num, uint8_t *data, uint16_t len); +uint8_t ch438_recv_data(uint8_t uart_num, uint8_t *data); #endif