generated from hulk/gd32f4xx_template_cmake_vscode
FilmForge: RS485 data link (USART0+DE PA8) and NTC temp (PC5 ADC0)
This commit is contained in:
+4
-7
@@ -36,6 +36,7 @@ OF SUCH DAMAGE.
|
||||
#include "systick.h"
|
||||
#include "uart.h"
|
||||
#include "uart_ring_buffer.h"
|
||||
#include "rs485.h"
|
||||
#include "led.h"
|
||||
#include "board_config.h"
|
||||
|
||||
@@ -141,16 +142,12 @@ void SysTick_Handler(void) {
|
||||
delay_decrement();
|
||||
}
|
||||
|
||||
/* 调试串口静态绑定 USART1(PA2/PA3),直接调用其处理函数。
|
||||
若业务改用其它串口,同步修改 board_config.h 的 UART_* 并在此补对应 IRQHandler。 */
|
||||
/* 串口中断静态绑定:USART0 = RS485 数据口(rs485.c),USART1 = debug 串口(uart.c)。
|
||||
若业务改用其它串口,同步修改 board_config.h 并在此调整对应 IRQHandler。 */
|
||||
void USART0_IRQHandler(void) {
|
||||
usart0_irq_handler();
|
||||
rs485_irq_handler();
|
||||
}
|
||||
|
||||
void USART1_IRQHandler(void) {
|
||||
usart1_irq_handler();
|
||||
}
|
||||
|
||||
void USART2_IRQHandler(void) {
|
||||
usart2_irq_handler();
|
||||
}
|
||||
|
||||
+25
-44
@@ -1,51 +1,21 @@
|
||||
/*!
|
||||
\file main.c
|
||||
\brief GD32F4xx 工程模板入口(LED 心跳 + 串口收发框架)
|
||||
\brief FilmForge 热压模具温控固件入口
|
||||
|
||||
基于 GD32E23x 工程模板移植,目标芯片 GD32F405RET6(Cortex-M4 @168MHz,512KB Flash)。
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2025, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
自制热压模具(塑型 PC 膜):加热驱动 + 测温(NTC)+ RS485 数据口。
|
||||
基于 GD32F4xx 工程模板,目标芯片 GD32F405RET6(Cortex-M4 @168MHz)。
|
||||
*/
|
||||
|
||||
#include "gd32f4xx.h"
|
||||
#include "systick.h"
|
||||
#include "uart.h"
|
||||
#include "uart_ring_buffer.h"
|
||||
#include "rs485.h"
|
||||
#include "ntc.h"
|
||||
#include "led.h"
|
||||
#include <stdio.h>
|
||||
#include "board_config.h"
|
||||
|
||||
/* TODO: 以下模块尚未从 GD32E23x 工程移植,编译验证通过后逐步补充:
|
||||
* - i2c.c/i2c.h I2C 主机读写驱动(硬件 I2C0 + 总线恢复)
|
||||
* - command.c/h 串口命令协议解析(D5 帧格式)
|
||||
* 移植时将对应文件加入 CMakeLists.txt 的 TARGET_SRC 即可。
|
||||
*/
|
||||
|
||||
/*!
|
||||
\brief main function
|
||||
\param[in] none
|
||||
@@ -61,22 +31,33 @@ int main(void)
|
||||
uart_ring_buffer_init();
|
||||
uart_init();
|
||||
|
||||
rs485_init();
|
||||
ntc_init();
|
||||
|
||||
#if DEBUG_MODE == CFG_ENABLE
|
||||
printf("Hello World!\r\n");
|
||||
printf("GD32F405 template, flash size: %u KB\r\n", GD32_FLASH_SIZE_KB);
|
||||
printf("FilmForge FW %s, built %s\r\n", PROJECT_VERSION, BUILD_DATE);
|
||||
printf("RS485 data link ready, NTC ready\r\n");
|
||||
#endif
|
||||
|
||||
#if SEGGER_RTT_DETECTION == CFG_ENABLE
|
||||
RTT_printf(0, "Hello World!\r\n");
|
||||
RTT_printf(0, "FilmForge FW\r\n");
|
||||
#endif
|
||||
printf("Hello World!\r\n");
|
||||
|
||||
/* ========== Command Testing ========== */
|
||||
|
||||
/* ========== */
|
||||
|
||||
while(1){
|
||||
/* TODO: command_process(); 命令模块移植后启用 */
|
||||
/* RS485 数据口处理(拉通阶段:回显) */
|
||||
rs485_process();
|
||||
|
||||
/* debug 串口周期打印 NTC 温度(约 1s 一次) */
|
||||
#if DEBUG_MODE == CFG_ENABLE
|
||||
{
|
||||
static uint16_t temp_report_counter = 0;
|
||||
if (++temp_report_counter >= 100U) { /* 主循环 10ms 一圈 → 1s */
|
||||
temp_report_counter = 0;
|
||||
printf("NTC temp: %.1f C\r\n", ntc_read_temperature());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
delay_ms(10);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
#include "ntc.h"
|
||||
#include "gd32f4xx_adc.h"
|
||||
#include "gd32f4xx_rcu.h"
|
||||
#include "gd32f4xx_gpio.h"
|
||||
#include "board_config.h"
|
||||
#include <math.h>
|
||||
|
||||
/**
|
||||
* @brief 配置 NTC 引脚(PC5 模拟输入)与 ADC0 常规通道。
|
||||
*/
|
||||
static void ntc_gpio_adc_config(void) {
|
||||
/* 使能 GPIOC 与 ADC0 时钟 */
|
||||
rcu_periph_clock_enable(NTC_GPIO_RCU);
|
||||
rcu_periph_clock_enable(NTC_ADC_RCU);
|
||||
|
||||
/* PC5 模拟输入模式 */
|
||||
gpio_mode_set(NTC_GPIO_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, NTC_GPIO_PIN);
|
||||
|
||||
/* ADC0 独立模式,常规通道软件触发、单次转换、右对齐 */
|
||||
adc_sync_mode_config(ADC_SYNC_MODE_INDEPENDENT);
|
||||
adc_special_function_config(NTC_ADC, ADC_CONTINUOUS_MODE, DISABLE);
|
||||
adc_special_function_config(NTC_ADC, ADC_INSERTED_CHANNEL, DISABLE);
|
||||
adc_external_trigger_config(NTC_ADC, ADC_ROUTINE_CHANNEL, EXTERNAL_TRIGGER_DISABLE);
|
||||
adc_data_alignment_config(NTC_ADC, ADC_DATAALIGN_RIGHT);
|
||||
adc_channel_length_config(NTC_ADC, ADC_ROUTINE_CHANNEL, 1U);
|
||||
adc_routine_channel_config(NTC_ADC, 0U, NTC_ADC_CHANNEL, NTC_SAMPLETIME);
|
||||
|
||||
adc_enable(NTC_ADC);
|
||||
adc_calibration_enable(NTC_ADC);
|
||||
}
|
||||
|
||||
void ntc_init(void) {
|
||||
ntc_gpio_adc_config();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 触发一次转换并读取 12bit 原始值。
|
||||
*/
|
||||
static uint16_t ntc_read_raw_once(void) {
|
||||
adc_flag_clear(NTC_ADC, ADC_FLAG_EOC);
|
||||
adc_software_trigger_enable(NTC_ADC, ADC_ROUTINE_CHANNEL);
|
||||
|
||||
/* 等待转换完成(EOC) */
|
||||
while (SET != adc_flag_get(NTC_ADC, ADC_FLAG_EOC)) {}
|
||||
return (uint16_t)adc_routine_data_read(NTC_ADC);
|
||||
}
|
||||
|
||||
float ntc_read_temperature(void) {
|
||||
uint32_t sum = 0U;
|
||||
|
||||
/* 多次采样均值降噪 */
|
||||
for (uint8_t i = 0; i < NTC_SAMPLE_COUNT; i++) {
|
||||
sum += ntc_read_raw_once();
|
||||
}
|
||||
float adc_val = (float)sum / (float)NTC_SAMPLE_COUNT;
|
||||
|
||||
/* 分压点电压:上拉 R_PULL 在 VREF 侧,NTC 接 GND 侧 */
|
||||
float voltage = adc_val * NTC_VREF / NTC_ADC_MAX;
|
||||
|
||||
/* 反解 NTC 阻值:V = VREF * R / (R_PULL + R) => R = R_PULL * V / (VREF - V) */
|
||||
if (voltage <= 0.0f || voltage >= NTC_VREF) {
|
||||
/* 开路/短路等异常,返回 -273.15 表示无效 */
|
||||
return -273.15f;
|
||||
}
|
||||
float r_ntc = NTC_R_PULL * voltage / (NTC_VREF - voltage);
|
||||
|
||||
/* B 值公式:1/T = 1/T25 + ln(R/R25)/B */
|
||||
float t_k = 1.0f / (1.0f / NTC_T25 + logf(r_ntc / NTC_R25) / (float)NTC_B_VALUE);
|
||||
return t_k - 273.15f;
|
||||
}
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
#include "rs485.h"
|
||||
#include "gd32f4xx_usart.h"
|
||||
#include "gd32f4xx_rcu.h"
|
||||
#include "gd32f4xx_gpio.h"
|
||||
#include "board_config.h"
|
||||
#include "uart.h"
|
||||
|
||||
/* 独立接收环形缓冲区(与 debug 串口的 uart_ring_buffer 隔离),
|
||||
采用"预留一格"区分空/满,最大可用容量为 RS485_RX_BUFFER_SIZE-1 */
|
||||
static __IO uint8_t rs485_rx_buffer[RS485_RX_BUFFER_SIZE];
|
||||
static __IO uint8_t rs485_write_index = 0;
|
||||
static __IO uint8_t rs485_read_index = 0;
|
||||
|
||||
static inline uint32_t rs485_irq_save(void) {
|
||||
uint32_t primask = __get_PRIMASK();
|
||||
__disable_irq();
|
||||
return primask;
|
||||
}
|
||||
|
||||
static inline void rs485_irq_restore(uint32_t primask) {
|
||||
if ((primask & 0x1) == 0) {
|
||||
__enable_irq();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 配置 RS485 收发引脚(PA9 TX / PA10 RX 复用,DE PA8 推挽输出)。
|
||||
*/
|
||||
static void rs485_gpio_config(void) {
|
||||
/* 使能 GPIOA 和 USART0 时钟 */
|
||||
rcu_periph_clock_enable(RS485_GPIO_RCU);
|
||||
rcu_periph_clock_enable(RS485_RCU);
|
||||
|
||||
/* PA9 为 USART0_TX,PA10 为 USART0_RX(AF7) */
|
||||
gpio_af_set(RS485_GPIO_PORT, GPIO_AF_7, RS485_TX_PIN | RS485_RX_PIN);
|
||||
|
||||
gpio_mode_set(RS485_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, RS485_TX_PIN | RS485_RX_PIN);
|
||||
gpio_output_options_set(RS485_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, RS485_TX_PIN | RS485_RX_PIN);
|
||||
|
||||
/* DE 引脚为普通推挽输出,默认接收态 */
|
||||
rcu_periph_clock_enable(RS485_DE_RCU);
|
||||
gpio_mode_set(RS485_DE_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, RS485_DE_PIN);
|
||||
gpio_output_options_set(RS485_DE_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, RS485_DE_PIN);
|
||||
gpio_bit_reset(RS485_DE_PORT, RS485_DE_PIN);
|
||||
}
|
||||
|
||||
void rs485_init(void) {
|
||||
rs485_gpio_config();
|
||||
|
||||
/* 配置波特率、数据位、停止位等 */
|
||||
usart_deinit(RS485_PHY);
|
||||
usart_word_length_set(RS485_PHY, USART_WL_8BIT);
|
||||
usart_stop_bit_set(RS485_PHY, USART_STB_1BIT);
|
||||
usart_parity_config(RS485_PHY, USART_PM_NONE);
|
||||
usart_baudrate_set(RS485_PHY, RS485_BAUDRATE);
|
||||
usart_receive_config(RS485_PHY, USART_RECEIVE_ENABLE);
|
||||
usart_transmit_config(RS485_PHY, USART_TRANSMIT_ENABLE);
|
||||
|
||||
usart_enable(RS485_PHY);
|
||||
|
||||
/* 使能接收非空中断 */
|
||||
nvic_irq_enable(RS485_IRQ, 0, 0);
|
||||
usart_interrupt_enable(RS485_PHY, USART_INT_RBNE);
|
||||
}
|
||||
|
||||
void rs485_send(const uint8_t *data, uint16_t len) {
|
||||
/* 进入发送态 */
|
||||
gpio_bit_set(RS485_DE_PORT, RS485_DE_PIN);
|
||||
|
||||
for (uint16_t i = 0; i < len; i++) {
|
||||
/* 等待发送缓冲区空 */
|
||||
while (RESET == usart_flag_get(RS485_PHY, USART_FLAG_TBE)) {}
|
||||
usart_data_transmit(RS485_PHY, data[i]);
|
||||
}
|
||||
/* 等待最后一字节移位完成,再切回接收态(避免截断尾字节) */
|
||||
while (RESET == usart_flag_get(RS485_PHY, USART_FLAG_TC)) {}
|
||||
|
||||
/* 回到接收态 */
|
||||
gpio_bit_reset(RS485_DE_PORT, RS485_DE_PIN);
|
||||
}
|
||||
|
||||
uint8_t rs485_rx_available(void) {
|
||||
uint8_t w = rs485_write_index;
|
||||
uint8_t r = rs485_read_index;
|
||||
return (uint8_t)((w + RS485_RX_BUFFER_SIZE - r) % RS485_RX_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
int rs485_rx_get(void) {
|
||||
if (rs485_read_index == rs485_write_index) return -1; /* 空 */
|
||||
uint8_t data = rs485_rx_buffer[rs485_read_index];
|
||||
rs485_read_index = (rs485_read_index + 1) % RS485_RX_BUFFER_SIZE;
|
||||
return data;
|
||||
}
|
||||
|
||||
void rs485_process(void) {
|
||||
while (rs485_rx_available() > 0) {
|
||||
int b = rs485_rx_get();
|
||||
if (b < 0) {
|
||||
break;
|
||||
}
|
||||
/* 拉通阶段:原样回发 RS485,同时转发 debug 串口便于观察 */
|
||||
rs485_send((const uint8_t *)&b, 1);
|
||||
debug_uart_write((uint8_t)b);
|
||||
}
|
||||
}
|
||||
|
||||
void rs485_irq_handler(void) {
|
||||
/* 处理USART0的接收中断 */
|
||||
if (usart_interrupt_flag_get(RS485_PHY, USART_INT_FLAG_RBNE)) {
|
||||
uint8_t data = usart_data_receive(RS485_PHY);
|
||||
uint32_t primask = rs485_irq_save();
|
||||
uint8_t next = (rs485_write_index + 1) % RS485_RX_BUFFER_SIZE;
|
||||
if (next != rs485_read_index) {
|
||||
/* 缓冲区未满 */
|
||||
rs485_rx_buffer[rs485_write_index] = data;
|
||||
rs485_write_index = next;
|
||||
}
|
||||
/* 缓冲满时丢弃 */
|
||||
rs485_irq_restore(primask);
|
||||
}
|
||||
|
||||
/* 处理USART0的空闲中断(帧间隔提示,后续协议解析用) */
|
||||
if (usart_interrupt_flag_get(RS485_PHY, USART_INT_FLAG_IDLE)) {
|
||||
usart_interrupt_flag_clear(RS485_PHY, USART_INT_FLAG_IDLE);
|
||||
}
|
||||
}
|
||||
+6
-46
@@ -10,20 +10,12 @@ void uart_init(void) {
|
||||
rcu_periph_clock_enable(UART_GPIO_RCU);
|
||||
rcu_periph_clock_enable(UART_RCU);
|
||||
|
||||
/* 配置 PA9 为 USART0_TX,PA10 为 USART0_RX(AF7) */
|
||||
/* 配置 PA2 为 USART1_TX,PA3 为 USART1_RX(AF7),debug 口纯串口 */
|
||||
gpio_af_set(UART_GPIO_PORT, GPIO_AF_7, UART_TX_PIN | UART_RX_PIN);
|
||||
|
||||
gpio_mode_set(UART_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, UART_TX_PIN | UART_RX_PIN);
|
||||
gpio_output_options_set(UART_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, UART_TX_PIN | UART_RX_PIN);
|
||||
|
||||
#if RS485_MODE == CFG_ENABLE
|
||||
/* 配置 RS485 DE 引脚为普通推挽输出(默认接收态) */
|
||||
rcu_periph_clock_enable(RS485_DE_RCU);
|
||||
gpio_mode_set(RS485_DE_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, RS485_DE_PIN);
|
||||
gpio_output_options_set(RS485_DE_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, RS485_DE_PIN);
|
||||
gpio_bit_reset(RS485_DE_PORT, RS485_DE_PIN);
|
||||
#endif
|
||||
|
||||
/* 配置波特率、数据位、停止位等 */
|
||||
usart_deinit(UART_PHY);
|
||||
usart_word_length_set(UART_PHY, USART_WL_8BIT);
|
||||
@@ -47,40 +39,21 @@ void uart_rx_irq_resume(void) {
|
||||
usart_interrupt_enable(UART_PHY, USART_INT_RBNE);
|
||||
}
|
||||
|
||||
#if RS485_MODE == CFG_ENABLE
|
||||
void rs485_de_set(void) {
|
||||
gpio_bit_set(RS485_DE_PORT, RS485_DE_PIN); /* 发送态 */
|
||||
void debug_uart_write(uint8_t byte) {
|
||||
/* 等待发送缓冲区空后写入 debug 串口 */
|
||||
while (RESET == usart_flag_get(DEBUG_UART, USART_FLAG_TBE)) {}
|
||||
usart_data_transmit(DEBUG_UART, byte);
|
||||
}
|
||||
|
||||
void rs485_de_clear(void) {
|
||||
gpio_bit_reset(RS485_DE_PORT, RS485_DE_PIN); /* 接收态 */
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/* 具体的中断处理函数实现 */
|
||||
/******************************************************************************/
|
||||
|
||||
void usart0_irq_handler(void) {
|
||||
// 处理USART0的接收中断
|
||||
if(usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) {
|
||||
uint8_t data = usart_data_receive(USART0);
|
||||
// 使用原有的环形缓冲区处理逻辑
|
||||
(void)uart_ring_buffer_put(data); // 缓冲满时丢弃,返回值可用于统计
|
||||
}
|
||||
|
||||
// 处理USART0的空闲中断
|
||||
if(usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE)) {
|
||||
usart_interrupt_flag_clear(USART0, USART_INT_FLAG_IDLE);
|
||||
// 在这里添加空闲中断处理逻辑
|
||||
}
|
||||
}
|
||||
|
||||
void usart1_irq_handler(void) {
|
||||
// 处理USART1的接收中断
|
||||
if(usart_interrupt_flag_get(USART1, USART_INT_FLAG_RBNE)) {
|
||||
uint8_t data = usart_data_receive(USART1);
|
||||
(void)uart_ring_buffer_put(data);
|
||||
(void)uart_ring_buffer_put(data); // 缓冲满时丢弃,返回值可用于统计
|
||||
}
|
||||
|
||||
// 处理USART1的空闲中断
|
||||
@@ -89,19 +62,6 @@ void usart1_irq_handler(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void usart2_irq_handler(void) {
|
||||
// 处理USART2的接收中断
|
||||
if(usart_interrupt_flag_get(USART2, USART_INT_FLAG_RBNE)) {
|
||||
uint8_t data = usart_data_receive(USART2);
|
||||
(void)uart_ring_buffer_put(data);
|
||||
}
|
||||
|
||||
// 处理USART2的空闲中断
|
||||
if(usart_interrupt_flag_get(USART2, USART_INT_FLAG_IDLE)) {
|
||||
usart_interrupt_flag_clear(USART2, USART_INT_FLAG_IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
/* 调试串口初始化(与 uart_init 相同配置的独立入口,便于单独初始化打印口) */
|
||||
void debug_usart_init(void)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user