[N32G457] 基于RT-Thread和N32G457的简易便捷式可调电压源

本文介绍了使用RT-Thread操作系统和国民技术N32G457芯片设计的一款便携式可调电压源。设计目标是解决外出测试时因电源问题带来的困扰,能输出1~35V电压,最大电流可达5A。采用RT-Thread的shell界面进行电压和电流设置,并实现了PID控制、过流保护及正弦波输出等功能。硬件设计包括N32G457最小系统板和定制测试板,通过ADC采集和处理数据,通过shell命令进行参数调整。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述

本文是RT-Thread用户@chengjili 原创发布,是用于参加RT-Thread与国民技术联手推出N32G457 RT-Thread设计大赛,原文:https://club.rt-thread.org/ask/article/3423.html

本设计是用来参加《创新“芯”引擎 | 国民技术N32G457 RT-Thread设计大赛》的作品。初衷是由于做军品要求国产化,所以最近也一直在测试国内不同厂家的32芯片的性能以及开发便捷性和最重要的稳定性等问题。之前也一直在用RTT做开发。浏览官网的时候发现有这个比赛,就顺便参加一下。至于做什么,肯定不能做我工作上的东西,都是军品保密的。只能想一些简单的。正好想到平常测试,特别是外出测试,经常因为电源问题而苦恼。于是想做一款简易的可调电压源,这样只需要带一个充电宝,就可以输出1~35V的电压,峰值电流基本能达到5A以上。也就可以驱动大多数的设备了。当然,功耗大的设备需要大充电宝才能工作时间长一些,但至少解决了供电电压不匹配的问题,可以应急使用了。
由于此比赛要求用官方给的核心板做开发,所以计划先简单实现一下主体功能。后面再具体做板实现整体功能。这次的测试硬件如下图,N32的最小系统板加一块我这边做其它测试的板子。这块板子只用了LTC3780部分的电路。
国民技术核心板2.jpg
具体电路如下图:
image.png
其中TEC-对地就是最终的电源输出接口,TEC_DAC为输出电压调整端口,接N32板的PA4引脚。TEC_i为输出电流检测端口,接N32板的PC1引脚。电源输出对地飞了个110K和10K的分压电阻,分压短点接N32板的PC0引脚,用于测量输出电压值(暂时没有对测量电压进行标定)。
测试版没有做显示界面(不太想飞线接屏了🤣)。取而代之的是shell界面。设置电压和电流值也用的shell命令。后面做电路的时候再改成显示屏和按键以及编码器旋钮的交互。测试界面如下:
image.png
具体实现了shell命令修改电压值,电流值。输出电压和电流反馈的ADC采集。实时显示当前输出功率。PID控制输出电压值。电流超过电流设置值时触发限流保护,降低电压。按特定波形输出电压的功能,暂时只做了正弦信号的。这个功能后续有需求再继续扩展其它信号。
程序方面,自认为RTT自带的一些驱动,效率不是很高,只适合特定场合的简单使用,或者算是提供了一个demo。实现具体功能的话,建议自己重写底层驱动。比如这次用的shell底层串口驱动框架和ADC驱动框架。我日常使用,大多数都是用其它系统板通过shell命令配置当前板子的各运行参数,这样比起人手输入命令,传输数据量就要高很多。底层处理效率低的话就会出现丢数据,丢指令和串口配置参数的时候CPU占用率过高的问题,所以要适应这种场合我都是要重写底层驱动,加入收发FIFO。读写都只对软件的FIFO接口,不用等待硬件的真正的发送和接收完成,提高了代码执行效率。但这次的测试功能,都是人手输入shell命令,所以这部分驱动我没有再改动,就用的原有的,针对于这种测试需求倒是足够了。但参加比赛,总要在代码上有点贡献,所以这次主要改动的是ADC的底层驱动,加入了个人在工作中对ADC使用的一些不成熟的理解,希望能帮助到有需要的朋友。下面做详细说明:
如下是官方驱动,enable ADC通道和读ADC数据的代码:
```
static rt_err_t n32_adc_enabled(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled)
{
ADC_Module *n32_adc_handler;
ADC_InitType ADC_InitStructure;
RT_ASSERT(device != RT_NULL);
n32_adc_handler = device->parent.user_data;

n32_msp_adc_init(n32_adc_handler);

ADC_InitStruct(&ADC_InitStructure);
ADC_InitStructure.WorkMode              = ADC_WORKMODE_INDEPENDENT;
ADC_InitStructure.MultiChEn             = DISABLE;
ADC_InitStructure.ContinueConvEn        = DISABLE;
ADC_InitStructure.ExtTrigSelect         = ADC_EXT_TRIGCONV_NONE;
ADC_InitStructure.DatAlign              = ADC_DAT_ALIGN_R;
ADC_InitStructure.ChsNumber             = 1;
ADC_Init(n32_adc_handler, &ADC_InitStructure);

/* ADCx regular channels configuration */
ADC_ConfigRegularChannel(n32_adc_handler, n32_adc_get_channel(channel), 1, ADC_SAMP_TIME_28CYCLES5);

if (((n32_adc_handler == ADC2) || (n32_adc_handler == ADC2))
    && ((n32_adc_get_channel(channel) == ADC_CH_16) || (n32_adc_get_channel(channel) == ADC_CH_18)))
{
    ADC_EnableTempSensorVrefint(ENABLE);
}

/* Enable ADCx */
ADC_Enable(n32_adc_handler, ENABLE);

/* Start ADCx calibration */
ADC_StartCalibration(n32_adc_handler);
/* Check the end of ADCx calibration */
while(ADC_GetCalibrationStatus(n32_adc_handler));

if (enabled)
{
    /* Enable ADC1 */
    ADC_Enable(n32_adc_handler, ENABLE);
}
else
{
    /* Enable ADCx */
    ADC_Enable(n32_adc_handler, DISABLE);
}

return RT_EOK;

}
static rt_err_t n32_get_adc_value(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value)
{
ADC_Module *n32_adc_handler;

RT_ASSERT(device != RT_NULL);
RT_ASSERT(value != RT_NULL);

n32_adc_handler = device->parent.user_data;

/* Start ADCx Software Conversion */
ADC_EnableSoftwareStartConv(n32_adc_handler, ENABLE);

/* Wait for the ADC to convert */
while(ADC_GetFlagStatus(n32_adc_handler, ADC_FLAG_ENDC) == RESET);

/* get ADC value */
*value = ADC_GetDat(n32_adc_handler);

return RT_EOK;

}

首先enable里面初始化ADC就已经写死了关掉了多通道采集,关掉了连续转换。规则组中也只能加入一个通道。所以,同一时刻只能enable一个通道,转换完毕后再enable下一个通道。每次读取都要使能软件触发转换,然后等待转换完成,然后再读取转换结果返回。这现然不是高效的做法,while等待的时候CPU什么都做不了,也不能调度去执行其它线程的任务。只适用于很偶然的读取一下ADC数据。而大多数读取ADC数据基本都是要读取大量数据,做一些平滑滤波或中值滤波,最终得到一些稳定的数据。现然这个框架很难实现此功能,就算勉强用一个线程频繁的去读取ADC数据来实现此功能,那估计强大的32芯片也基本干不了别的了。144M的主频,说高不高,但说低也不低,又有FPU可以并行执行一些浮点运算指令,利用好了还是可以完成很多事情的。感觉官方ADC驱动框架也基本只限于简单的demo使用。于是加入了如下自己的ADC驱动程序:

#define ADC1_BUF1_UPDATE_EVENT 0x00000001
#define ADC1_BUF2_UPDATE_EVENT 0x00000002

#define ADC_VREFINT_VAL 1497.89

#ifdef BSP_USING_USER_ADC1
user_adc_config adc1_config =
{
.ADC_Handler = ADC1,
.name = “user_adc1”,
.RCC_APB2_PERIPH_GPIOX = RCC_APB2_PERIPH_GPIOC,
.regular_channels = {
{ADC_CH_18, RT_NULL, RT_NULL}, //rank1 Vrefint
{ADC_CH_16, RT_NULL, RT_NULL}, //rank2 temp_cup
{ADC_CH_6, GPIOC, GPIO_PIN_0}, //rank3 out_voltage
{ADC_CH_7, GPIOC, GPIO_PIN_1} //rank4 out_current
}
};
uint16_t user_adc1_val_buf[2][USER_ADC1_AVE_N * USER_ADC1_REGULAR_CH];
float adc1_ave_buf[USER_ADC1_REGULAR_CH-1];
rt_thread_t adc_data_handle_thread;
rt_event_t adc_update_event;
#endif

#ifdef BSP_USING_USER_ADC2
user_adc_config adc2_config =
{
.ADC_

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值