1.first_drv write(LED驱动)

first_drv.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>

static struct class *firstdrv_class;
static struct class_device	*firstdrv_class_dev;

volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL;


static int first_drv_open(struct inode *inode, struct file *file)
{
	//printk("first_drv_open\n");
	/* 配置GPF4,5,6为输出 */
	*gpfcon &= ~((0x3<<(4*2)) | (0x3<<(5*2)) | (0x3<<(6*2)));
	*gpfcon |= ((0x1<<(4*2)) | (0x1<<(5*2)) | (0x1<<(6*2)));
	return 0;
}

static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
	int val;

	//printk("first_drv_write\n");

	copy_from_user(&val, buf, count); //	copy_to_user();

	if (val == 1)
	{
		// 点灯
		*gpfdat &= ~((1<<4) | (1<<5) | (1<<6));
	}
	else
	{
		// 灭灯
		*gpfdat |= (1<<4) | (1<<5) | (1<<6);
	}
	
	return 0;
}

static struct file_operations first_drv_fops = {
    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open   =   first_drv_open,     
	.write	=	first_drv_write,	   
};


int major;
static int first_drv_init(void)
{
	major = register_chrdev(0, "first_drv", &first_drv_fops); // 注册, 告诉内核

	firstdrv_class = class_create(THIS_MODULE, "firstdrv");

	firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */

	gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
	gpfdat = gpfcon + 1;

	return 0;
}

static void first_drv_exit(void)
{
	unregister_chrdev(major, "first_drv"); // 卸载

	class_device_unregister(firstdrv_class_dev);
	class_destroy(firstdrv_class);
	iounmap(gpfcon);
}

module_init(first_drv_init);
module_exit(first_drv_exit);


MODULE_LICENSE("GPL");

Makefile

KERN_DIR = /work/system/linux-2.6.22.6

all:
	make -C $(KERN_DIR) M=`pwd` modules 

clean:
	make -C $(KERN_DIR) M=`pwd` modules clean
	rm -rf modules.order

obj-m	+= first_drv.o

first_app.c


#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

/* firstdrvtest on
  * firstdrvtest off
  */
int main(int argc, char **argv)
{
	int fd;
	int val = 1;
	fd = open("/dev/xyz", O_RDWR);
	if (fd < 0)
	{
		printf("can't open!\n");
	}
	if (argc != 2)
	{
		printf("Usage :\n");
		printf("%s <on|off>\n", argv[0]);
		return 0;
	}

	if (strcmp(argv[1], "on") == 0)
	{
		val  = 1;
	}
	else
	{
		val = 0;
	}
	
	write(fd, &val, 4);
	return 0;
}

最简单的驱动,一般人都看的懂!

但是,里面的函数是否真的理解透了,我打个大大的问号。

1.  major = register_chrdev(0, "fifth_drv", &sencod_drv_fops);

int register_chrdev(unsigned int major, const char *name,
		    const struct file_operations *fops)
{
	struct char_device_struct *cd;
	struct cdev *cdev;
	char *s;
	int err = -ENOMEM;

	cd = __register_chrdev_region(major, 0, 256, name);
	if (IS_ERR(cd))
		return PTR_ERR(cd);
	
	cdev = cdev_alloc();
	if (!cdev)
		goto out2;

	cdev->owner = fops->owner;
	cdev->ops = fops;
	kobject_set_name(&cdev->kobj, "%s", name);
	for (s = strchr(kobject_name(&cdev->kobj),'/'); s; s = strchr(s, '/'))
		*s = '!';
		
	err = cdev_add(cdev, MKDEV(cd->major, 0), 256);
	if (err)
		goto out;

	cd->cdev = cdev;

	return major ? 0 : cd->major;
out:
	kobject_put(&cdev->kobj);
out2:
	kfree(__unregister_chrdev_region(cd->major, 0, 256));
	return err;
}

               __register_chrdev_region 

static struct char_device_struct *
__register_chrdev_region(unsigned int major, unsigned int baseminor,
			   int minorct, const char *name)
{
	struct char_device_struct *cd, **cp;
	int ret = 0;
	int i;

	cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
	if (cd == NULL)
		return ERR_PTR(-ENOMEM);

	mutex_lock(&chrdevs_lock);

	/* temporary */
	if (major == 0) {
		for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {
			if (chrdevs[i] == NULL)
				break;
		}

		if (i == 0) {
			ret = -EBUSY;
			goto out;
		}
		major = i;
		ret = major;
	}

	cd->major = major;
	cd->baseminor = baseminor;
	cd->minorct = minorct;
	strncpy(cd->name,name, 64);

	i = major_to_index(major);

	for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
		if ((*cp)->major > major ||
		    ((*cp)->major == major &&
		     (((*cp)->baseminor >= baseminor) ||
		      ((*cp)->baseminor + (*cp)->minorct > baseminor))))
			break;

	/* Check for overlapping minor ranges.  */
	if (*cp && (*cp)->major == major) {
		int old_min = (*cp)->baseminor;
		int old_max = (*cp)->baseminor + (*cp)->minorct - 1;
		int new_min = baseminor;
		int new_max = baseminor + minorct - 1;

		/* New driver overlaps from the left.  */
		if (new_max >= old_min && new_max <= old_max) {
			ret = -EBUSY;
			goto out;
		}

		/* New driver overlaps from the right.  */
		if (new_min <= old_max && new_min >= old_min) {
			ret = -EBUSY;
			goto out;
		}
	}

	cd->next = *cp;
	*cp = cd;
	mutex_unlock(&chrdevs_lock);
	return cd;
out:
	mutex_unlock(&chrdevs_lock);
	kfree(cd);
	return ERR_PTR(ret);
}

 cdev_alloc

struct cdev *cdev_alloc(void)
{
	struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
	if (p) {
		p->kobj.ktype = &ktype_cdev_dynamic;
		INIT_LIST_HEAD(&p->list);
		kobject_init(&p->kobj);
	}
	return p;
}
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
	p->dev = dev;
	p->count = count;
	return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
}

总结一下字符设备:

1.注册字符设备 major = register_chrdev(0, "fifth_drv", &sencod_drv_fops);

2.注册总线       fifthdrv_class = class_create(THIS_MODULE, "fifth_drv");

3.设备和总线联系   class_device_create(fifthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */

4.具体寄存器操作

    gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
    gpfdat = gpfcon + 1;

    gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
    gpgdat = gpgcon + 1;

今晚很晚了,暂时总结到这里

#include <stdio.h> #include "ls_io_ctrl.h" #include "ls_system.h" #include "ls_uart0.h" #include <math.h> #include "ls_spi.h" #include "sys_config.h" #include "io_comm.h" #include "led.h" #include "task.h" //#include "ad5322.h" #include "tla2518_A.h" #include "write_analog.h" #include "delay.h" #include "hv_voltage_ctrl.h" #include "mm32_device.h" #define LOG_TAG "main.c" #define LOG_LEVEL LOG_LEVEL_VERBOSE #include "logger.h" // 端口初始化函数 static void drv_port_init(void) { /***************PA端口*********/ io_ctrl.init(IO_CTRL_CURRENT_DECODE_0, IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_CURRENT_DECODE_1, IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_CURRENT_DECODE_2, IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_SELF_CHECK_CURRENT,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_STATE_LED4,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_LED,IO_MODE_OUTPUT_PP); io_ctrl.set(IO_CTRL_SELF_CHECK_CURRENT, IO_SET); io_ctrl.set(IO_CTRL_CURRENT_DECODE_0, IO_SET); io_ctrl.set(IO_CTRL_CURRENT_DECODE_1,IO_SET); io_ctrl.set(IO_CTRL_CURRENT_DECODE_2, IO_SET); io_ctrl.set(IO_CTRL_STATE_LED4,IO_SET); io_ctrl.set(IO_CTRL_LED,IO_SET); /***********PB端口***********/ io_ctrl.init(IO_CTRL_STATE_LED3,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_STATE_LED2,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_STATE_LED1,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_DAC_DECODE0,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_DAC_DECODE1,IO_MODE_OUTPUT_PP); io_ctrl.set(IO_CTRL_STATE_LED3, IO_SET); io_ctrl.set(IO_CTRL_STATE_LED2, IO_SET); io_ctrl.set(IO_CTRL_STATE_LED1,IO_SET); io_ctrl.set(IO_CTRL_HV_DAC_DECODE0,IO_SET); io_ctrl.set(IO_CTRL_HV_DAC_DECODE1,IO_SET); io_ctrl.init(IO_CTRL_HV_DAC_DECODE2,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_ADC_DECODE0,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_ADC_DECODE1,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_ADC_DECODE2,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_S2_DECODE0,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_S2_DECODE1,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_S2_DECODE2,IO_MODE_OUTPUT_PP); io_ctrl.set(IO_CTRL_HV_DAC_DECODE2, IO_SET); io_ctrl.set(IO_CTRL_HV_ADC_DECODE0, IO_SET); io_ctrl.set(IO_CTRL_HV_ADC_DECODE1,IO_SET); io_ctrl.set(IO_CTRL_HV_ADC_DECODE2,IO_SET); io_ctrl.set(IO_CTRL_HV_S2_DECODE0,IO_SET); io_ctrl.set(IO_CTRL_HV_S2_DECODE1,IO_SET); io_ctrl.set(IO_CTRL_HV_S2_DECODE2, IO_SET); /****PC端口****/ io_ctrl.init(IO_CTRL_HV_LEVEL,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_LV_LEVEL1,IO_MODE_OUTPUT_PP); //10V电平控制 io_ctrl.init(IO_CTRL_LV_LEVEL2,IO_MODE_OUTPUT_PP); //24V电平控制 io_ctrl.init(IO_CTRL_LV_LEVEL3,IO_MODE_OUTPUT_PP); //48V电平控制 io_ctrl.init(IO_CTRL_HV_S1_1,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_S1_2,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_S1_3,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_S1_4,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_S1_5,IO_MODE_OUTPUT_PP); io_ctrl.set(IO_CTRL_HV_LEVEL,IO_RESET); io_ctrl.set(IO_CTRL_LV_LEVEL1,IO_SET); io_ctrl.set(IO_CTRL_LV_LEVEL2,IO_SET); io_ctrl.set(IO_CTRL_LV_LEVEL3,IO_SET); io_ctrl.set(IO_CTRL_HV_S1_1,IO_SET); io_ctrl.set(IO_CTRL_HV_S1_2,IO_SET); io_ctrl.set(IO_CTRL_HV_S1_3,IO_SET); io_ctrl.set(IO_CTRL_HV_S1_4,IO_SET); io_ctrl.set(IO_CTRL_HV_S1_5,IO_SET); } // 底层硬件初始化函数 static void bsp_init(void) { ls_sys.sys_rcu_init(); // 系统时钟初始化 ls_sys.systick_init(); // 滴答定时器初始化 uart0.init(); // 串口0初始化 drv_port_init(); // 驱动端口初始化 io_comm.init(); // IO通信初始化 led_init(); // LED初始化 hv_voltage_init(); // 高压系统初始化 tla2518_A.init(); // TLA2518 ADC初始化 // ad5322.init(); // 初始化5个高压模块的DAC实例 xWriteAnalog1.vInit(&xWriteAnalog1, &xDacIcDev1); xWriteAnalog2.vInit(&xWriteAnalog2, &xDacIcDev2); xWriteAnalog3.vInit(&xWriteAnalog3, &xDacIcDev3); xWriteAnalog4.vInit(&xWriteAnalog4, &xDacIcDev4); xWriteAnalog5.vInit(&xWriteAnalog5, &xDacIcDev5); // 打印版本信息 uart0.send_bytes((mfU8_t *)VERSION_NAME, VERSION_SIZE); LOG_I("Building at %s %s",__DATE__,__TIME__); LOG_I("SystemCoreClock : %d",ls_sys.system_clock); } int main(void) { bsp_init(); // 初始化所有底层硬件 LOG_I("System device init ok!"); // ========== 高压模块1输出50V测试逻辑 ========== hv_error_t ret = hv_test_module1_output_50v(); if (ret != HV_ERR_SUCCESS) { // 测试失败:打印错误码 + 紧急停机 + 死循环保护 printf("Output 50V failed, error code: %d\n", ret); hv_voltage_shutdown(); // 强制关闭高压系统 while(1) { io_ctrl.set(IO_CTRL_LED, IO_RESET); DELAY_Ms(500); io_ctrl.set(IO_CTRL_LED, IO_SET); DELAY_Ms(500); } } printf("Output 50V success!\n"); // ========== 实时读取并校验输出电压 ========== float actual_vol = 0.0f; while(1) // 循环监测电压 { // 读取当前输出电压 if (hv_read_total_voltage(&actual_vol) != HV_ERR_SUCCESS) { printf("ADC read failed! Shutdown HV system.\n"); hv_voltage_shutdown(); // ADC读取失败,紧急停机 while(1); // 死循环保护 } // 打印当前电压 printf("Current output voltage: %.2fV\n", actual_vol); // 电压超限判断(50V±5%) if (fabsf(actual_vol - 50.0f) > 50.0f * 0.05f) { printf("Voltage out of range! Shutdown HV system.\n"); hv_voltage_shutdown(); // 电压超限,紧急停机 while(1); // 死循环保护 } DELAY_Ms(500); // 500ms刷新一次电压 } // 原任务启动逻辑(如需恢复,可注释上面的测试代码,启用下面一行) // task_start(); } /* int main(void) { bsp_init(); LOG_I("System device init ok!"); task_start(); return 0; } while(1) { // ========== 修正后的LED一秒一亮逻辑 ========== led_state = (led_state == IO_SET) ? IO_RESET : IO_SET; io_ctrl.set(IO_CTRL_LED, led_state); printf("LED state: %d (IO_SET=1, IO_RESET=0)\n", led_state); DELAY_Ms(500); */ /* int main(void) { bsp_init(); LOG_I("系统设备初始化完成!"); // 注释原任务启动函数,改为死循环实现电压切换 while(1) { // 输出48V:设置48V对应控制引脚 io_ctrl.set(IO_CTRL_LV_LEVEL3, IO_SET); ls_sys.delay_ms(50); // 延时50ms // 输出0V:拉低48V对应控制引脚(关闭48V输出) io_ctrl.set(IO_CTRL_LV_LEVEL3, IO_RESET); ls_sys.delay_ms(50); // 延时50ms } } */ #include "ls_system.h" #include <stdio.h> #include "write_analog.h" #include "hv_voltage_ctrl.h" #include <math.h> #include "ls_spi.h" #include "ls_io_ctrl.h" #include "delay.h" #include "hal_spi.h" #include "hal_gpio.h" #include "hal_rcc.h" #include "mm32_device.h" #include "tla2518_A.h" // 引入ADC驱动头文件,解决函数隐式声明警告 // 全局系统状态 static hv_system_status_t g_hv_sys_status = {0}; // -------------------------- 静态函数声明 -------------------------- static WriteAnalog_t* get_write_analog_instance(uint8_t module_id); // 获取对应模块的DAC实例 static bool check_module_version(uint8_t module_id); // 检查模块版本号 static void reset_all_modules(void); // 复位所有模块 /*********************** 测试函数:模块1输出50V ***********************/ hv_error_t hv_test_module1_output_50v(void) { // 1. 初始化高压系统 hv_error_t ret = hv_voltage_init(); if (ret != HV_ERR_SUCCESS) { return ret; } // 2. 安全优先:关闭所有模块的输出和使能 hv_voltage_shutdown(); DELAY_Ms(100); // 等待电压泄放 // 3. 配置模块1输出50V uint8_t target_module = 1; // 仅用模块1 float target_vol = 50.0f; // 目标电压50V hv_module_status_t* module = &g_hv_sys_status.modules[target_module - 1]; WriteAnalog_t* analog = get_write_analog_instance(target_module); DacIcDev_t* dac_dev = &xDacIcDev1 + (target_module - 1); // 校验模块/DAC实例有效性 if (analog == NULL || dac_dev == NULL) { hv_voltage_shutdown(); return HV_ERR_MODULE_INVALID; } // 4. 计算50V对应的DAC值(AD5623:2.5V→4095,高压模块增益20倍→2.5V×20=50V) uint16_t dac_val = (uint16_t)(target_vol / HV_MODULE_GAIN * 4095.0f / DAC_REF_VOLTAGE); dac_val = (dac_val > 4095) ? 4095 : dac_val; // 限制最大值 // 5. 发送DAC指令配置模块1电压 analog->vInit(analog, dac_dev); // 初始化模块1的DAC analog->vSetA(analog, dac_val); // 设置DAC值 // 6. 使能模块1并等待电压稳定 hv_set_s1_ex(target_module, 1); // 使能模块1 DELAY_Ms(500); // 模块电压稳定延时 // 7. 打开模块1的高压输出 hv_set_s2_ex(target_module, 1); DELAY_Ms(200); // 输出稳定延时 // 8. 更新系统状态 module->target_voltage = target_vol; module->dac_value = dac_val; module->is_enabled = true; g_hv_sys_status.active_module_cnt = 1; g_hv_sys_status.total_target_voltage = target_vol; // 9. 验证实际输出电压(误差±5%以内) float actual_vol = 0.0f; ret = hv_read_total_voltage(&actual_vol); if (ret != HV_ERR_SUCCESS) { hv_voltage_shutdown(); return HV_ERR_ADC_READ_FAILED; } // 校验电压误差(50V±5% → 47.5V ~ 52.5V) if (fabsf(actual_vol - target_vol) > target_vol * 0.05f) { hv_voltage_shutdown(); return HV_ERR_MODULE_FAULT; } // 10. 输出成功日志 printf("Module 1 output 50V success! Actual voltage: %.2fV\n", actual_vol); return HV_ERR_SUCCESS; } // -------------------------- 公共函数实现 ------------------------- /****************** 一、高压系统初始化 hv_voltage_init ************************ */ hv_error_t hv_voltage_init(void) { // 1. 初始化驱动层SPI(调用write_analog.c中的实现) spi_dac_global_init(); // 2. 初始化5个模块的DAC上层控制 for (uint8_t i = 0; i < HV_MODULE_COUNT; i++) { WriteAnalog_t* analog = get_write_analog_instance(i + 1); if (analog == NULL) return HV_ERR_MODULE_INVALID; // 初始化DAC analog->vInit(analog, &xDacIcDev1 + i); hv_set_s1_ex(i + 1, 0); // 禁用模块 hv_set_s2_ex(i + 1, 0); // 关闭高压输出 } // 3. 复位系统状态 reset_all_modules(); return HV_ERR_SUCCESS; } /********************** 二、设置总目标电压 *****************************/ hv_error_t hv_set_voltage(float vol) { // 1. 参数合法性校验 if (vol < HV_MODULE_MIN_VOLTAGE) { return HV_ERR_VOLTAGE_LOW; } if (vol > HV_TOTAL_MAX_VOLTAGE) { return HV_ERR_VOLTAGE_HIGH; } // 2. 计算需要的模块数量(向上取整) uint8_t modules_needed = (uint8_t)ceilf(vol / HV_MODULE_MAX_VOLTAGE); float voltage_per_module = vol / modules_needed; // 3. 确保每个模块电压不低于最小值(不足则增加模块数) if (voltage_per_module < HV_MODULE_MIN_VOLTAGE) { modules_needed = (uint8_t)ceilf(vol / HV_MODULE_MIN_VOLTAGE); voltage_per_module = vol / modules_needed; // 再次校验(避免极端情况) if (modules_needed > HV_MODULE_COUNT || voltage_per_module < HV_MODULE_MIN_VOLTAGE) { return HV_ERR_MODULE_INVALID; } } // 4. 先关闭所有高压输出和模块使能(安全优先) for (uint8_t i = 0; i < HV_MODULE_COUNT; i++) { hv_set_s2_ex(i + 1, 0); hv_set_s1_ex(i + 1, 0); g_hv_sys_status.modules[i].is_enabled = false; g_hv_sys_status.modules[i].is_faulty = false; } DELAY_Ms(100); // 等待电压泄放 // 5. 配置每个启用的模块 float total_calc_vol = 0.0f; for (uint8_t i = 0; i < modules_needed; i++) { hv_module_status_t* module = &g_hv_sys_status.modules[i]; WriteAnalog_t* analog = get_write_analog_instance(i + 1); DacIcDev_t* dac_dev = &xDacIcDev1 + i; if (analog == NULL || dac_dev == NULL) { hv_voltage_shutdown(); return HV_ERR_MODULE_INVALID; } // 计算当前模块电压(最后一个模块分摊剩余电压,避免误差) float module_vol = (i == modules_needed - 1) ? (vol - voltage_per_module * (modules_needed - 1)) : voltage_per_module; // 计算DAC值(AD5623:12位,2.5V参考,20倍增益) uint16_t dac_val = (uint16_t)(module_vol / HV_MODULE_GAIN * 4095.0f / DAC_REF_VOLTAGE); dac_val = (dac_val > 4095) ? 4095 : dac_val; // 发送DAC指令(确保DAC设备指针正确传入) analog->vSetA(analog, dac_val); // 更新模块状态 module->target_voltage = module_vol; module->dac_value = dac_val; module->is_enabled = true; total_calc_vol += module_vol; } // 6. 启用模块并等待稳定 for (uint8_t i = 0; i < modules_needed; i++) { hv_set_s1_ex(i + 1, 1); // 使能模块 } DELAY_Ms(500); // 模块电压稳定延时 // 7. 打开高压输出(按模块顺序,避免浪涌) for (uint8_t i = 0; i < modules_needed; i++) { hv_set_s2_ex(i + 1, 1); DELAY_Ms(10); // 模块间延时 } // 8. 更新系统状态 g_hv_sys_status.active_module_cnt = modules_needed; g_hv_sys_status.total_target_voltage = vol; // 9. 回读电压验证 float actual_vol = 0.0f; if (hv_read_total_voltage(&actual_vol) != HV_ERR_SUCCESS) { hv_voltage_shutdown(); return HV_ERR_ADC_READ_FAILED; } // 电压误差允许±5% if (fabsf(actual_vol - vol) > vol * 0.05f) { hv_voltage_shutdown(); return HV_ERR_MODULE_FAULT; } return HV_ERR_SUCCESS; } /**************** 三、读取总实际电压 hv_read_total_voltage ******************* */ hv_error_t hv_read_total_voltage(float* actual_vol) { if (actual_vol == NULL) return HV_ERR_ADC_READ_FAILED; float total_vol = 0.0f; bool read_ok = true; // 读取每个启用模块的输出电压 for (uint8_t i = 0; i < HV_MODULE_COUNT; i++) { hv_module_status_t* module = &g_hv_sys_status.modules[i]; if (!module->is_enabled) continue; // 读取ADC通道1(模块输出电压)- 调用TLA2518驱动 uint16_t adc_val = tla2518_A_get_sam_value(10, i*2); // 采样10次,模块i对应通道2i float module_vol = adc_val * ADC_MODULE_VOLTAGE_COEF; // 读取ADC通道2(高压线电压,交叉验证) uint16_t adc_line_val = tla2518_A_get_sam_value(10, i*2+1); float line_vol = adc_line_val * ADC_MODULE_VOLTAGE_COEF; // 读取ADC通道6(DAC反馈电压,验证DAC设置) uint16_t adc_dac_val = tla2518_A_get_sam_value(10, 6); float dac_vol = adc_dac_val * ADC_DAC_VOLTAGE_COEF; // 正确的DAC反馈电压期望值:DAC输出电压 = (模块目标电压 / 增益) float expected_dac_vol = module->target_voltage / HV_MODULE_GAIN; // 故障判断(误差超限标记故障) if (fabsf(module_vol - module->target_voltage) > module->target_voltage * 0.1f) { module->is_faulty = true; read_ok = false; } if (fabsf(line_vol - module_vol) > module_vol * 0.1f) { module->is_faulty = true; read_ok = false; } if (fabsf(dac_vol - expected_dac_vol) > 0.05f) { // DAC反馈误差±0.05V(更精准) module->is_faulty = true; read_ok = false; } module->actual_voltage = module_vol; total_vol += module_vol; } *actual_vol = total_vol; g_hv_sys_status.total_actual_voltage = total_vol; return read_ok ? HV_ERR_SUCCESS : HV_ERR_ADC_READ_FAILED; } /************************* 四、读取系统状态 hv_get_system_status **************************** */ hv_error_t hv_get_system_status(hv_system_status_t* status) { if (status == NULL) return HV_ERR_ADC_READ_FAILED; *status = g_hv_sys_status; return HV_ERR_SUCCESS; } /************************** 五、高压系统自检 hv_voltage_self_test *************** */ hv_error_t hv_voltage_self_test(void) { // 1. 复位所有模块 reset_all_modules(); DELAY_Ms(500); // 2. 检查所有模块版本号 for (uint8_t i = 0; i < HV_MODULE_COUNT; i++) { if (!check_module_version(i + 1)) { g_hv_sys_status.modules[i].is_faulty = true; hv_voltage_shutdown(); return HV_ERR_MODULE_FAULT; } } // 3. 逐个模块测试(输出50V,验证电压) for (uint8_t i = 0; i < HV_MODULE_COUNT; i++) { uint8_t module_id = i + 1; hv_module_status_t* module = &g_hv_sys_status.modules[i]; WriteAnalog_t* analog = get_write_analog_instance(module_id); DacIcDev_t* dac_dev = &xDacIcDev1 + i; if (analog == NULL || dac_dev == NULL) { hv_voltage_shutdown(); return HV_ERR_MODULE_INVALID; } // 关闭所有输出 for (uint8_t j = 0; j < HV_MODULE_COUNT; j++) { hv_set_s2_ex(j + 1, 0); hv_set_s1_ex(j + 1, 0); } DELAY_Ms(500); // 配置测试电压(50V) float test_vol = 50.0f; uint16_t dac_val = (uint16_t)(test_vol / HV_MODULE_GAIN * 4095.0f / DAC_REF_VOLTAGE); dac_val = (dac_val > 4095) ? 4095 : dac_val; // 启用模块并发送DAC指令 hv_set_s1_ex(module_id, 1); analog->vInit(analog, dac_dev); analog->vSetA(analog, dac_val); DELAY_Ms(500); // 打开该模块的高压输出 hv_set_s2_ex(module_id, 1); DELAY_Ms(200); // 读取测试数据(调用TLA2518驱动) uint16_t adc_module = tla2518_A_get_sam_value(10, i*2); // 模块输出电压 uint16_t adc_line = tla2518_A_get_sam_value(10, i*2+1); // 高压线电压 uint16_t adc_dac = tla2518_A_get_sam_value(10, 6); // DAC反馈电压 float module_vol = adc_module * ADC_MODULE_VOLTAGE_COEF; float line_vol = adc_line * ADC_MODULE_VOLTAGE_COEF; float dac_vol = adc_dac * ADC_DAC_VOLTAGE_COEF; float expected_dac_vol = test_vol / HV_MODULE_GAIN; // 故障判断(按模块说明文档逻辑) bool module_fault = false; if (fabsf(module_vol - test_vol) > test_vol * 0.1f && fabsf(line_vol - test_vol) > test_vol * 0.1f) { if (line_vol < 10.0f) { // 修正阈值:50V模块输出低于10V判定输入错误 module_fault = true; // 高压模块-高压输入错误 } else if (fabsf(dac_vol - expected_dac_vol) > 0.1f) { module_fault = true; // 高压模块-ADC/DAC错误 } else if (line_vol > 60.0f && fabsf(dac_vol - expected_dac_vol) <= 0.1f) { module_fault = true; // 高压模块-调压错误 } } // 读取版本号再次验证 if (!check_module_version(module_id)) { module_fault = true; } if (module_fault) { module->is_faulty = true; hv_set_s2_ex(module_id, 0); hv_set_s1_ex(module_id, 0); hv_voltage_shutdown(); return HV_ERR_MODULE_FAULT; } // 关闭当前模块测试 hv_set_s2_ex(module_id, 0); hv_set_s1_ex(module_id, 0); DELAY_Ms(100); } // 4. 测试通过,复位状态 reset_all_modules(); return HV_ERR_SUCCESS; } /*********************** 六、紧急停机 hv_voltage_shutdown ******************************************* */ void hv_voltage_shutdown(void) { // 关闭所有高压输出和模块使能 for (uint8_t i = 0; i < HV_MODULE_COUNT; i++) { hv_set_s2_ex(i + 1, 0); hv_set_s1_ex(i + 1, 0); g_hv_sys_status.modules[i].is_enabled = false; g_hv_sys_status.modules[i].is_faulty = false; } // 复位系统状态 g_hv_sys_status.active_module_cnt = 0; g_hv_sys_status.total_target_voltage = 0.0f; g_hv_sys_status.total_actual_voltage = 0.0f; } // -------------------------- 静态函数实现 -------------------------- static WriteAnalog_t* get_write_analog_instance(uint8_t module_id) { switch (module_id) { case 1: return &xWriteAnalog1; case 2: return &xWriteAnalog2; case 3: return &xWriteAnalog3; case 4: return &xWriteAnalog4; case 5: return &xWriteAnalog5; default: return NULL; } } static bool check_module_version(uint8_t module_id) { // 读取ADC通道7(版本号通道)- 调用TLA2518驱动 uint16_t adc_val = tla2518_A_get_sam_value(5, 7); float version_vol = adc_val * ADC_VERSION_COEF; // 版本号有效范围:0.5V~2.5V if (version_vol >= 0.5f && version_vol <= 2.5f) { g_hv_sys_status.modules[module_id - 1].version_voltage = version_vol; return true; } return false; } static void reset_all_modules(void) { for (uint8_t i = 0; i < HV_MODULE_COUNT; i++) { hv_module_status_t* module = &g_hv_sys_status.modules[i]; module->is_enabled = false; module->target_voltage = 0.0f; module->actual_voltage = 0.0f; module->dac_value = 0; module->is_faulty = false; module->version_voltage = 0.0f; } g_hv_sys_status.active_module_cnt = 0; g_hv_sys_status.total_target_voltage = 0.0f; g_hv_sys_status.total_actual_voltage = 0.0f; } // -------------------------- 底层硬件接口实现 -------------------------- /************ 1. 控制模块使能引脚 S1_EX hv_set_s1_ex *************** */ void hv_set_s1_ex(uint8_t module_id, uint8_t enable) { // 校验模块ID(1~5) if (module_id < 1 || module_id > HV_MODULE_COUNT) return; // 模块ID到S1引脚的映射(需确保ls_io_ctrl.h中定义这些宏) static const io_ctrl_id_et s1_pins[HV_MODULE_COUNT] = { IO_CTRL_HV_S1_1, // 模块1 IO_CTRL_HV_S1_2, // 模块2 IO_CTRL_HV_S1_3, // 模块3 IO_CTRL_HV_S1_4, // 模块4 IO_CTRL_HV_S1_5 // 模块5 }; io_ctrl_id_et io_id = s1_pins[module_id - 1]; // 静态数组标记是否已初始化,避免重复初始化 static bool s1_inited[HV_MODULE_COUNT] = {false}; if (!s1_inited[module_id - 1]) { io_ctrl.init(io_id, IO_MODE_OUTPUT_PP); // 推挽输出 s1_inited[module_id - 1] = true; } // 使能:IO_RESET(低电平),禁用:IO_SET(高电平) io_ctrl.set(io_id, enable ? IO_RESET : IO_SET); } /************ 2. 读取 ADC 值 hv_spi_adc_read(兼容底层SPI,备用接口) ********************** */ uint16_t hv_spi_adc_read(uint8_t module_id, uint8_t channel) { // 1. 参数合法性校验 if (module_id < 1 || module_id > HV_MODULE_COUNT || channel < 1 || channel > 7) { return 0; } // 2. 模块到ADC CS引脚的映射(3位解码:decode0=bit0, decode1=bit1, decode2=bit2) io_ctrl_id_et cs_pins[3] = {IO_CTRL_HV_ADC_DECODE0, IO_CTRL_HV_ADC_DECODE1, IO_CTRL_HV_ADC_DECODE2}; uint8_t decode_val = module_id; // 模块1=1(001), 2=2(010), 3=3(011),4=4(100),5=5(101) // 初始化所有CS解码引脚(移除is_init判断:ls_io_ctrl无该字段,重复初始化安全) for (uint8_t i=0; i<3; i++) { io_ctrl.init(cs_pins[i], IO_MODE_OUTPUT_PP); // 直接初始化 io_ctrl.set(cs_pins[i], IO_SET); // 初始高电平 } // 3. 设置解码引脚,选中目标模块 io_ctrl.set(cs_pins[0], (decode_val & 0x01) ? IO_RESET : IO_SET); io_ctrl.set(cs_pins[1], (decode_val & 0x02) ? IO_RESET : IO_SET); io_ctrl.set(cs_pins[2], (decode_val & 0x04) ? IO_RESET : IO_SET); ls_sys.delay_us(2); // 稳定延时 // 4. 替换未定义的tla2518_A_read_adv为工程已实现的tla2518_A_get_sam_value // 参数:采样次数(10次) + 通道号(channel-1,适配TLA2518通道0-6对应1-7) uint16_t adc_val = tla2518_A_get_sam_value(10, channel-1); // 5. 复位解码引脚 for (uint8_t i=0; i<3; i++) { io_ctrl.set(cs_pins[i], IO_SET); } // 6. 转换为12位ADC值 return adc_val; } /********* 3. 控制高压输出引脚 hv_set_s2_ex ************** */ void hv_set_s2_ex(uint8_t module_id, uint8_t enable) { // 校验模块ID(1~5) if (module_id < 1 || module_id > HV_MODULE_COUNT) return; // S2解码引脚(3位:decode0=bit0, decode1=bit1, decode2=bit2) static const io_ctrl_id_et s2_pins[3] = { IO_CTRL_HV_S2_DECODE0, IO_CTRL_HV_S2_DECODE1, IO_CTRL_HV_S2_DECODE2 }; // 初始化解码引脚(仅第一次) static bool s2_inited = false; if (!s2_inited) { for (uint8_t i=0; i<3; i++) { io_ctrl.init(s2_pins[i], IO_MODE_OUTPUT_PP); io_ctrl.set(s2_pins[i], IO_SET); // 初始高电平 } s2_inited = true; } if (enable) { // 3位二进制解码模块1-5:1=001,2=010,3=011,4=100,5=101 uint8_t decode_val = module_id; for (uint8_t i=0; i<3; i++) { io_ctrl.set(s2_pins[i], (decode_val & (1<<i)) ? IO_RESET : IO_SET); } } else { // 禁用时所有解码引脚置高 for (uint8_t i=0; i<3; i++) { io_ctrl.set(s2_pins[i], IO_SET); } } } /************ 4. 延时函数实现 *************** */ void DELAY_Ms(uint32_t ms) { ls_sys.delay_ms(ms); } #ifndef HV_VOLTAGE_CTRL_H #define HV_VOLTAGE_CTRL_H #include <stdint.h> #include <stdbool.h> #include <stddef.h> #include "write_analog.h" // -------------------------- 硬件参数宏定义 -------------------------- #define HV_MODULE_COUNT 5 // 总高压模块数 #define HV_MODULE_MIN_VOLTAGE 10.0f // 单个模块最低输出电压(V) #define HV_MODULE_MAX_VOLTAGE 100.0f // 单个模块最高输出电压(V) #define HV_TOTAL_MAX_VOLTAGE (HV_MODULE_COUNT * HV_MODULE_MAX_VOLTAGE) // 总最高电压(500V) // AD5623 核心参数(12位DAC,内部2.5V参考) #define DAC_REF_VOLTAGE 2.5f // DAC参考电压(V) #define HV_MODULE_GAIN 20.0f // 高压模块增益(DAC输出×20=模块输出) #define DAC_VOLTAGE_TO_VALUE (4095.0f / (HV_MODULE_MAX_VOLTAGE / HV_MODULE_GAIN)) // 81.9f // ADC系数(校准后) #define ADC_MODULE_VOLTAGE_COEF (HV_MODULE_MAX_VOLTAGE / 4095.0f) // 100V/4095≈0.02442f #define ADC_DAC_VOLTAGE_COEF (DAC_REF_VOLTAGE / 4095.0f) // DAC反馈电压系数(2.5V/4095) #define ADC_VERSION_COEF (5.0f / 4095.0f) // 版本号电压系数(5V参考) // 错误码定义 typedef enum { HV_ERR_SUCCESS = 0, // 成功 HV_ERR_VOLTAGE_LOW, // 电压低于最小值 HV_ERR_VOLTAGE_HIGH, // 电压高于最大值 HV_ERR_MODULE_INVALID, // 模块配置无效 HV_ERR_SPI_FAILED, // SPI通信失败 HV_ERR_ADC_READ_FAILED, // ADC读取失败 HV_ERR_MODULE_FAULT // 模块故障 } hv_error_t; // 单个模块状态结构体 typedef struct { bool is_enabled; // 是否启用 float target_voltage; // 目标电压(V) float actual_voltage; // 实际电压(V) uint16_t dac_value; // DAC设置值(12位:0-4095) bool is_faulty; // 是否故障 float version_voltage; // 版本号电压(V) } hv_module_status_t; // 系统整体状态结构体 typedef struct { hv_module_status_t modules[HV_MODULE_COUNT]; // 各模块状态 uint8_t active_module_cnt; // 活跃模块数 float total_target_voltage; // 总目标电压(V) float total_actual_voltage; // 总实际电压(V) } hv_system_status_t; // -------------------------- 底层硬件接口声明 -------------------------- /** * @brief 控制模块使能引脚 S1_EX * @param module_id:模块ID(1-5) * @param enable:1=使能(低电平),0=禁用(高电平) * @return 无 */ void hv_set_s1_ex(uint8_t module_id, uint8_t enable); /** * @brief 控制高压输出引脚 S2_EX(3位解码) * @param module_id:模块ID(1-5) * @param enable:1=打开输出,0=关闭输出 * @return 无 */ void hv_set_s2_ex(uint8_t module_id, uint8_t enable); /** * @brief 读取ADC值(适配TLA2518) * @param module_id:模块ID(1-5) * @param channel:ADC通道(1-7) * @return 12位ADC原始值(0-4095) */ uint16_t hv_spi_adc_read(uint8_t module_id, uint8_t channel); /** * @brief 毫秒级延时 * @param ms:延时时间(ms) * @return 无 */ void DELAY_Ms(uint32_t ms); /** * @brief SPI DAC全局初始化(实现位于write_analog.c) * @param 无 * @return 无 */ void spi_dac_global_init(void); // -------------------------- 高压控制核心接口 -------------------------- /** * @brief 高压系统初始化 * @param 无 * @return hv_error_t:错误码 */ hv_error_t hv_voltage_init(void); /** * @brief 设置总目标电压 * @param vol:总目标电压(V),范围:10V ~ 500V * @return hv_error_t:错误码 */ hv_error_t hv_set_voltage(float vol); /** * @brief 读取总实际电压 * @param actual_vol:输出参数,总实际电压(V) * @return hv_error_t:错误码 */ hv_error_t hv_read_total_voltage(float* actual_vol); /** * @brief 读取系统状态 * @param status:输出参数,系统状态结构体 * @return hv_error_t:错误码 */ hv_error_t hv_get_system_status(hv_system_status_t* status); /** * @brief 高压系统自检(逐个模块测试50V输出) * @param 无 * @return hv_error_t:错误码(HV_ERR_SUCCESS=自检通过) */ hv_error_t hv_voltage_self_test(void); /** * @brief 关闭高压系统(紧急停机) * @param 无 * @return 无 */ void hv_voltage_shutdown(void); /** * @brief 测试函数:模块1输出50V * @param 无 * @return hv_error_t:错误码 */ hv_error_t hv_test_module1_output_50v(void); #endif // HV_VOLTAGE_CTRL_H #include <stdint.h> #include "write_analog.h" #include "ls_spi.h" #include "ls_io_ctrl.h" #include "ls_system.h" #include "hal_conf.h" #include "delay.h" // --------------------------声明所有static函数 -------------------------- static void vGpioConfig(void); static void vSpiConfig(void); static void vSpiTransmit(DacIcDev_t* pxDev); static void vInitDacIcDev(DacIcDev_t* pxDev); static void vWriteDacIcDev(DacIcDev_t* pxDev, uint16_t usDacValue, WRITE_ANALOG_CHANNEL_E eChannel); static void vTestDacIcDev(DacIcDev_t* pxDev); static void vInitWriteAnalog(WriteAnalog_t* pxWriteAnalog, DacIcDev_t* pxDev); static void vSetA(WriteAnalog_t* pxWriteAnalog, uint16_t usDacValue); static void vSetB(WriteAnalog_t* pxWriteAnalog, uint16_t usDacValue); // -------------------------- 核心引脚定义 -------------------------- #define AD5623_CS_PORT GPIOC #define AD5623_CS_PIN GPIO_Pin_6 #define AD5623_LDAC_PORT GPIOB #define AD5623_LDAC_PIN GPIO_Pin_0 #define AD5623_CLR_PORT GPIOB #define AD5623_CLR_PIN GPIO_Pin_1 #define AD5623_CS_SET() GPIO_SetBits(AD5623_CS_PORT, AD5623_CS_PIN) #define AD5623_CS_RESET() GPIO_ResetBits(AD5623_CS_PORT, AD5623_CS_PIN) // -------------------------- 全局对象声明 -------------------------- DacIcDev_t xDacIcDev1 = {.vInit = vInitDacIcDev}; WriteAnalog_t xWriteAnalog1 = {.vInit = vInitWriteAnalog}; DacIcDev_t xDacIcDev2 = {.vInit = vInitDacIcDev}; WriteAnalog_t xWriteAnalog2 = {.vInit = vInitWriteAnalog}; DacIcDev_t xDacIcDev3 = {.vInit = vInitDacIcDev}; WriteAnalog_t xWriteAnalog3 = {.vInit = vInitWriteAnalog}; DacIcDev_t xDacIcDev4 = {.vInit = vInitDacIcDev}; WriteAnalog_t xWriteAnalog4 = {.vInit = vInitWriteAnalog}; DacIcDev_t xDacIcDev5 = {.vInit = vInitDacIcDev}; WriteAnalog_t xWriteAnalog5 = {.vInit = vInitWriteAnalog}; // -------------------------- GPIO初始化 -------------------------- static void vGpioConfig(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA | RCC_AHBENR_GPIOB | RCC_AHBENR_GPIOC, ENABLE); // SPI1引脚(GPIOB13=SCK, GPIOB15=MOSI)- 复用推挽 GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_0); GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_0); GPIO_StructInit(&GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOB, &GPIO_InitStruct); // MISO(GPIOB14)- 浮空输入 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_FLOATING; GPIO_Init(GPIOB, &GPIO_InitStruct); // CS(GPIOC6)- 推挽输出,默认拉高 GPIO_InitStruct.GPIO_Pin = AD5623_CS_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(AD5623_CS_PORT, &GPIO_InitStruct); AD5623_CS_SET(); // LDAC(GPIOB0)- 拉低永久使能更新 GPIO_InitStruct.GPIO_Pin = AD5623_LDAC_PIN; GPIO_Init(AD5623_LDAC_PORT, &GPIO_InitStruct); GPIO_ResetBits(AD5623_LDAC_PORT, AD5623_LDAC_PIN); // CLR(GPIOB1)- 拉高禁用清零 GPIO_InitStruct.GPIO_Pin = AD5623_CLR_PIN; GPIO_Init(AD5623_CLR_PORT, &GPIO_InitStruct); GPIO_SetBits(AD5623_CLR_PORT, AD5623_CLR_PIN); } // -------------------------- SPI初始化 -------------------------- static void vSpiConfig(void) { SPI_InitTypeDef SPI_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2ENR_SPI1, ENABLE); SPI_DeInit(SPI1); // AD5623模式0:CPOL=Low,CPHA=1Edge SPI_StructInit(&SPI_InitStruct); SPI_InitStruct.SPI_Mode = SPI_Mode_Master; SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; SPI_InitStruct.SPI_DataWidth = 8; SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB; SPI_Init(SPI1, &SPI_InitStruct); SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Rx); SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Tx); SPI_Cmd(SPI1, ENABLE); } // -------------------------- SPI传输 -------------------------- static void vSpiTransmit(DacIcDev_t* pxDev) { // 16位指令:[3位操作码][3位地址][12位数据] uint16_t tx_data = ((pxDev->xDacIcReg.xBits.ucC0_2 & 0x07) << 13) | ((pxDev->xDacIcReg.xBits.ucA0_2 & 0x07) << 10) | (pxDev->xDacIcReg.xBits.usD0_11 & 0x0FFF); __NOP();__NOP(); AD5623_CS_RESET(); __NOP();__NOP(); // 发送高8位 SPI_SendData(SPI1, (uint8_t)(tx_data >> 8)); while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT)); while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_RXAVL)); SPI_ReceiveData(SPI1); __NOP();__NOP(); // 发送低8位 SPI_SendData(SPI1, (uint8_t)(tx_data & 0xFF)); while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT)); while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_RXAVL)); SPI_ReceiveData(SPI1); __NOP();__NOP(); AD5623_CS_SET(); __NOP();__NOP(); } // -------------------------- DAC设备初始化 -------------------------- static void vInitDacIcDev(DacIcDev_t* pxDev) { if(NULL == pxDev) return; vGpioConfig(); vSpiConfig(); // 绑定函数指针 pxDev->vTest = vTestDacIcDev; pxDev->vWrite = vWriteDacIcDev; // 1. 软件复位所有通道 pxDev->xDacIcReg.ulData = 0; pxDev->xDacIcReg.xBits.ucC0_2 = DAC_RST; pxDev->xDacIcReg.xBits.ucA0_2 = DAC_ALL; pxDev->xDacIcReg.xBits.usD0_11 = 0; vSpiTransmit(pxDev); // 2. 配置LDAC:禁用A/B通道锁存 pxDev->xDacIcReg.ulData = 0; pxDev->xDacIcReg.xBits.ucC0_2 = LDAC_REG_SET; pxDev->xDacIcReg.xBits.usD0_11 = 0x0003; vSpiTransmit(pxDev); // 3. 启用内部2.5V参考(A/B通道) pxDev->xDacIcReg.ulData = 0; pxDev->xDacIcReg.xBits.ucC0_2 = REF_REG_SET; pxDev->xDacIcReg.xBits.ucA0_2 = DAC_A; pxDev->xDacIcReg.xBits.usD0_11 = 0x0001; vSpiTransmit(pxDev); pxDev->xDacIcReg.ulData = 0; pxDev->xDacIcReg.xBits.ucC0_2 = REF_REG_SET; pxDev->xDacIcReg.xBits.ucA0_2 = DAC_B; pxDev->xDacIcReg.xBits.usD0_11 = 0x0001; vSpiTransmit(pxDev); // 初始输出0V pxDev->vWrite(pxDev, 0, WRITE_ANALOG_CHANNEL_A); pxDev->vWrite(pxDev, 0, WRITE_ANALOG_CHANNEL_B); } // -------------------------- DAC写入 -------------------------- static void vWriteDacIcDev(DacIcDev_t* pxDev, uint16_t usDacValue, WRITE_ANALOG_CHANNEL_E eChannel) { if(NULL == pxDev || usDacValue > 0x0FFF) return; pxDev->xDacIcReg.ulData = 0; pxDev->xDacIcReg.xBits.ucA0_2 = (eChannel == WRITE_ANALOG_CHANNEL_A) ? DAC_A : DAC_B; pxDev->xDacIcReg.xBits.ucC0_2 = WR_UPD_DAC; pxDev->xDacIcReg.xBits.usD0_11 = usDacValue; vSpiTransmit(pxDev); } // -------------------------- DAC测试 -------------------------- static void vTestDacIcDev(DacIcDev_t* pxDev) { if(NULL == pxDev) return; while(1) { pxDev->vWrite(pxDev, 0, WRITE_ANALOG_CHANNEL_A); pxDev->vWrite(pxDev, 0, WRITE_ANALOG_CHANNEL_B); DELAY_Ms(500); pxDev->vWrite(pxDev, 819, WRITE_ANALOG_CHANNEL_A); pxDev->vWrite(pxDev, 819, WRITE_ANALOG_CHANNEL_B); DELAY_Ms(500); pxDev->vWrite(pxDev, 1638, WRITE_ANALOG_CHANNEL_A); pxDev->vWrite(pxDev, 1638, WRITE_ANALOG_CHANNEL_B); DELAY_Ms(500); pxDev->vWrite(pxDev, 2458, WRITE_ANALOG_CHANNEL_A); pxDev->vWrite(pxDev, 2458, WRITE_ANALOG_CHANNEL_B); DELAY_Ms(500); pxDev->vWrite(pxDev, 3277, WRITE_ANALOG_CHANNEL_A); pxDev->vWrite(pxDev, 3277, WRITE_ANALOG_CHANNEL_B); DELAY_Ms(500); pxDev->vWrite(pxDev, 4095, WRITE_ANALOG_CHANNEL_A); pxDev->vWrite(pxDev, 4095, WRITE_ANALOG_CHANNEL_B); DELAY_Ms(500); } } // -------------------------- WriteAnalog初始化 -------------------------- static void vInitWriteAnalog(WriteAnalog_t* pxWriteAnalog, DacIcDev_t* pxDev) { if(NULL == pxWriteAnalog || NULL == pxDev) return; pxDev->vInit(pxDev); pxWriteAnalog->pxDev = pxDev; pxWriteAnalog->vSetA = vSetA; pxWriteAnalog->vSetB = vSetB; pxWriteAnalog->vSetA(pxWriteAnalog, 0); pxWriteAnalog->vSetB(pxWriteAnalog, 0); } // -------------------------- 通道A/B设置 -------------------------- static void vSetA(WriteAnalog_t* pxWriteAnalog, uint16_t usDacValue) { if(NULL == pxWriteAnalog) return; pxWriteAnalog->pxDev->vWrite(pxWriteAnalog->pxDev, usDacValue, WRITE_ANALOG_CHANNEL_A); } static void vSetB(WriteAnalog_t* pxWriteAnalog, uint16_t usDacValue) { if(NULL == pxWriteAnalog) return; pxWriteAnalog->pxDev->vWrite(pxWriteAnalog->pxDev, usDacValue, WRITE_ANALOG_CHANNEL_B); } // -------------------------- 全局SPI初始化 -------------------------- void spi_dac_global_init(void) { vSpiConfig(); } #ifndef WRITE_ANALOG_H #define WRITE_ANALOG_H #include "stdint.h" // 配置开关 #define WRITE_ANALOG_USING_LOCK 0 #define AD5623R5 0 #define DAC_IC_TYPE AD5623R5 // DAC参数 #define DAC_IC_BIT 12 // 12位DAC #define DAC_IC_REF 2.5f // 内部参考电压2.5V // 通道枚举 typedef enum { WRITE_ANALOG_CHANNEL_A, // DAC A通道 WRITE_ANALOG_CHANNEL_B // DAC B通道 }WRITE_ANALOG_CHANNEL_E; // AD5623操作码(3位) #define WR_REGR 0x00 // 写寄存器 #define UPD_DAC_REG 0x01 // 更新DAC #define WR_REG_UPD_ALL_DAC_LDAC 0x02 // 写寄存器并更新所有DAC #define WR_UPD_DAC 0x03 // 写并更新指定DAC #define DAC_OFF 0x04 // DAC掉电 #define DAC_RST 0x05 // 软件复位 #define LDAC_REG_SET 0x06 // 配置LDAC寄存器 #define REF_REG_SET 0x07 // 配置参考电压寄存器 // AD5623地址码(3位) #define DAC_A 0x00 // 通道A #define DAC_B 0x01 // 通道B #define DAC_ALL 0x07 // 所有通道 typedef union { struct { uint16_t usD0_11: 12; // bit9~0: 12位DAC数据 uint8_t ucA0_2: 3; // bit12~10: 地址码 uint8_t ucC0_2: 3; // bit15~13: 操作码 }xBits; uint16_t usData; // 16位指令整体 uint32_t ulData; }DacIcReg_t; // DAC设备结构体 typedef struct DacIcDev_t { DacIcReg_t xDacIcReg; void (*vInit)(struct DacIcDev_t* pxDev); void (*vWrite)(struct DacIcDev_t* pxDev, uint16_t usDacValue, WRITE_ANALOG_CHANNEL_E eChannel); void (*vTest)(struct DacIcDev_t* pxDev); }DacIcDev_t; // WriteAnalog控制结构体 typedef struct WriteAnalog_t { DacIcDev_t* pxDev; void (*vInit)(struct WriteAnalog_t* pxWriteAnalog, DacIcDev_t* pxDev); void (*vSetA)(struct WriteAnalog_t* pxWriteAnalog, uint16_t usDacValue); void (*vSetB)(struct WriteAnalog_t* pxWriteAnalog, uint16_t usDacValue); }WriteAnalog_t; // 全局对象声明 extern DacIcDev_t xDacIcDev1; extern DacIcDev_t xDacIcDev2; extern DacIcDev_t xDacIcDev3; extern DacIcDev_t xDacIcDev4; extern DacIcDev_t xDacIcDev5; extern WriteAnalog_t xWriteAnalog1; extern WriteAnalog_t xWriteAnalog2; extern WriteAnalog_t xWriteAnalog3; extern WriteAnalog_t xWriteAnalog4; extern WriteAnalog_t xWriteAnalog5; // 全局函数声明 void spi_dac_global_init(void); #endif 第一步:修改 AD5632 驱动文件 (放在驱动) 修改ad5632的write analog.c与write analog.h两个驱动文件放在驱动层里面 第二步:创建高压控制文件 (放在 Application 层) 目标:根据目标电压,计算出需要动用哪些模块、每个模块需要输出多少电压,然后调用驱动层的接口去执行,并完成电压读取。 创建 2 个新文件,hv_voltage_ctrl.c和hv_voltage_ctrl.h放在 Application/ 文件夹下。 (结合高压电源模块说明进行编写) hv_voltage_ctrl.h头文件:声明 set_vol 函数和电压读取函数的接口,定义必要的宏等。 hv_voltage_ctrl.c: 完成以下任务 1、set_vol(unit vol)1)根据设定电压确认需要用到多少个模块,总共5个 高压模块输出电压 = DAC 输出电压 × 放大系数 (2)计算每个模块需要输出多少电压 (3)往每个模块发送DAC指令 (4)先关闭低压输出通道,再打开高压输出通道。 2、完成电压读取 帮我检查一下这些文件有没有问题,为什么输出不了高压50V,还需要别的文件参考请告诉我.
最新发布
11-28
#include "ls_system.h" #include <stdio.h> #include "write_analog.h" #include "hv_voltage_ctrl.h" #include <math.h> #include "ls_spi.h" #include "ls_io_ctrl.h" #include "delay.h" #include "hal_spi.h" #include "hal_gpio.h" #include "hal_rcc.h" #include "mm32_device.h" // 全局系统状态 static hv_system_status_t g_hv_sys_status = {0}; // -------------------------- 静态函数声明 -------------------------- static WriteAnalog_t* get_write_analog_instance(uint8_t module_id); // 获取对应模块的DAC实例 static bool check_module_version(uint8_t module_id); // 检查模块版本号 static void reset_all_modules(void); // 复位所有模块 // -------------------------- 公共函数实现 ------------------------- /*********************** 测试函数:模块1输出50V ***********************/ hv_error_t hv_test_module1_output_50v(void) { // 1. 初始化高压系统(确保SPI/DAC/IO已初始化) hv_error_t ret = hv_voltage_init(); if (ret != HV_ERR_SUCCESS) { return ret; } // 2. 安全优先:关闭所有模块的输出和使能 hv_voltage_shutdown(); DELAY_Ms(100); // 等待电压泄放 // 3. 配置模块1输出50V uint8_t target_module = 1; // 仅用模块1 float target_vol = 50.0f; // 目标电压50V hv_module_status_t* module = &g_hv_sys_status.modules[target_module - 1]; WriteAnalog_t* analog = get_write_analog_instance(target_module); DacIcDev_t* dac_dev = &xDacIcDev1 + (target_module - 1); // 校验模块/DAC实例有效性 if (analog == NULL || dac_dev == NULL) { hv_voltage_shutdown(); return HV_ERR_MODULE_INVALID; } // 4. 计算50V对应的DAC值(12位DAC,范围0~4095) uint16_t dac_val = (uint16_t)(target_vol * DAC_VOLTAGE_TO_VALUE); dac_val = (dac_val > 4095) ? 4095 : dac_val; // 限制最大值 // 计算结果:50 * 33.42857142857 = 1671.428 → 取整1671(有效范围,无溢出) // 5. 发送DAC指令配置模块1电压 analog->vInit(analog, dac_dev); // 初始化模块1的DAC analog->vSetA(analog, dac_val); // 设置DAC值 // 6. 使能模块1并等待电压稳定 hv_set_s1_ex(target_module, 1); // 使能模块1 DELAY_Ms(500); // 模块电压稳定延时 // 7. 打开模块1的高压输出 hv_set_s2_ex(target_module, 1); DELAY_Ms(200); // 输出稳定延时 // 8. 更新系统状态 module->target_voltage = target_vol; module->dac_value = dac_val; module->is_enabled = true; g_hv_sys_status.active_module_cnt = 1; g_hv_sys_status.total_target_voltage = target_vol; // 9. 验证实际输出电压(误差±5%以内) float actual_vol = 0.0f; ret = hv_read_total_voltage(&actual_vol); if (ret != HV_ERR_SUCCESS) { hv_voltage_shutdown(); return HV_ERR_ADC_READ_FAILED; } // 校验电压误差(50V±5% → 47.5V ~ 52.5V) if (fabsf(actual_vol - target_vol) > target_vol * 0.05f) { hv_voltage_shutdown(); return HV_ERR_MODULE_FAULT; } // 10. 输出成功日志 printf("Module 1 output 50V success! Actual voltage: %.2fV\n", actual_vol); return HV_ERR_SUCCESS; } /******************一、高压系统初始化 hv_voltage_init-************************ */ hv_error_t hv_voltage_init(void) { // 1. 初始化驱动层SPI spi_dac_global_init(); // 2. 初始化5个模块的DAC上层控制 for (uint8_t i = 0; i < HV_MODULE_COUNT; i++) { WriteAnalog_t* analog = get_write_analog_instance(i + 1); if (analog == NULL) return HV_ERR_MODULE_INVALID; // 初始化DAC analog->vInit(analog, &xDacIcDev1 + i); hv_set_s1_ex(i + 1, 0); // 禁用模块 hv_set_s2_ex(i + 1, 0); // 关闭高压输出 } // 3. 复位系统状态 reset_all_modules(); return HV_ERR_SUCCESS; } /**********************二、设置总目标电压*****************************/ hv_error_t hv_set_voltage(float vol) { // 1. 参数合法性校验 if (vol < HV_MODULE_MIN_VOLTAGE) { return HV_ERR_VOLTAGE_LOW; } if (vol > HV_TOTAL_MAX_VOLTAGE) { return HV_ERR_VOLTAGE_HIGH; } // 2. 计算需要的模块数量(向上取整) uint8_t modules_needed = (uint8_t)ceilf(vol / HV_MODULE_MAX_VOLTAGE); float voltage_per_module = vol / modules_needed; // 3. 确保每个模块电压不低于最小值(不足则增加模块数) if (voltage_per_module < HV_MODULE_MIN_VOLTAGE) { modules_needed = (uint8_t)ceilf(vol / HV_MODULE_MIN_VOLTAGE); voltage_per_module = vol / modules_needed; // 再次校验(避免极端情况) if (modules_needed > HV_MODULE_COUNT || voltage_per_module < HV_MODULE_MIN_VOLTAGE) { return HV_ERR_MODULE_INVALID; } } // 4. 先关闭所有高压输出和模块使能(安全优先) for (uint8_t i = 0; i < HV_MODULE_COUNT; i++) { hv_set_s2_ex(i + 1, 0); hv_set_s1_ex(i + 1, 0); g_hv_sys_status.modules[i].is_enabled = false; g_hv_sys_status.modules[i].is_faulty = false; } DELAY_Ms(100); // 等待电压泄放 // 5. 配置每个启用的模块 float total_calc_vol = 0.0f; for (uint8_t i = 0; i < modules_needed; i++) { hv_module_status_t* module = &g_hv_sys_status.modules[i]; WriteAnalog_t* analog = get_write_analog_instance(i + 1); DacIcDev_t* dac_dev = &xDacIcDev1 + i; if (analog == NULL || dac_dev == NULL) { hv_voltage_shutdown(); return HV_ERR_MODULE_INVALID; } // 计算当前模块电压(最后一个模块分摊剩余电压,避免误差) float module_vol = (i == modules_needed - 1) ? (vol - voltage_per_module * (modules_needed - 1)) : voltage_per_module; // 计算DAC值(12位范围限制) uint16_t dac_val = (uint16_t)(module_vol * DAC_VOLTAGE_TO_VALUE); dac_val = (dac_val > 4095) ? 4095 : dac_val; // 发送DAC指令(确保DAC设备指针正确传入) analog->vSetA(analog, dac_val); // 更新模块状态 module->target_voltage = module_vol; module->dac_value = dac_val; module->is_enabled = true; total_calc_vol += module_vol; } // 6. 启用模块并等待稳定 for (uint8_t i = 0; i < modules_needed; i++) { hv_set_s1_ex(i + 1, 1); // 使能模块 } DELAY_Ms(500); // 模块电压稳定延时 // 7. 打开高压输出 //hv_set_s2_ex(1, 1); // 优先打开第一个模块的输出 for (uint8_t i = 0; i < modules_needed; i++) { hv_set_s2_ex(i + 1, 1); DELAY_Ms(10); // 模块间延时 } // 8. 更新系统状态 g_hv_sys_status.active_module_cnt = modules_needed; g_hv_sys_status.total_target_voltage = vol; // 9. 回读电压验证 float actual_vol = 0.0f; if (hv_read_total_voltage(&actual_vol) != HV_ERR_SUCCESS) { hv_voltage_shutdown(); return HV_ERR_ADC_READ_FAILED; } // 电压误差允许±5% if (fabsf(actual_vol - vol) > vol * 0.05f) { hv_voltage_shutdown(); return HV_ERR_MODULE_FAULT; } return HV_ERR_SUCCESS; } /****************三、读取总实际电压 hv_read_total_voltage******************* */ hv_error_t hv_read_total_voltage(float* actual_vol) { if (actual_vol == NULL) return HV_ERR_ADC_READ_FAILED; float total_vol = 0.0f; bool read_ok = true; // 读取每个启用模块的输出电压 for (uint8_t i = 0; i < HV_MODULE_COUNT; i++) { hv_module_status_t* module = &g_hv_sys_status.modules[i]; if (!module->is_enabled) continue; // 读取ADC通道1(模块输出电压) uint16_t adc_val = hv_spi_adc_read(i + 1, 1); float module_vol = adc_val * ADC_MODULE_VOLTAGE_COEF; // 读取ADC通道2(高压线电压,交叉验证) uint16_t adc_line_val = hv_spi_adc_read(i + 1, 2); float line_vol = adc_line_val * ADC_MODULE_VOLTAGE_COEF; // 读取ADC通道6(DAC反馈电压,验证DAC设置) uint16_t adc_dac_val = hv_spi_adc_read(i + 1, 6); float dac_vol = adc_dac_val * ADC_DAC_VOLTAGE_COEF; float expected_dac_vol = module->target_voltage / (DAC_VOLTAGE_TO_VALUE * (5.0f / 4095.0f)); // 故障判断(误差超限标记故障) if (fabsf(module_vol - module->target_voltage) > module->target_voltage * 0.1f) { module->is_faulty = true; read_ok = false; } if (fabsf(line_vol - module_vol) > module_vol * 0.1f) { module->is_faulty = true; read_ok = false; } if (fabsf(dac_vol - expected_dac_vol) > 0.5f) { // DAC反馈误差±0.5V module->is_faulty = true; read_ok = false; } module->actual_voltage = module_vol; total_vol += module_vol; } *actual_vol = total_vol; g_hv_sys_status.total_actual_voltage = total_vol; return read_ok ? HV_ERR_SUCCESS : HV_ERR_ADC_READ_FAILED; } /*************************四、 读取系统状态 hv_get_system_status**************************** */ hv_error_t hv_get_system_status(hv_system_status_t* status) { if (status == NULL) return HV_ERR_ADC_READ_FAILED; *status = g_hv_sys_status; return HV_ERR_SUCCESS; } /**************************五、高压系统自检 hv_voltage_self_test*************** */ hv_error_t hv_voltage_self_test(void) { // 1. 复位所有模块 reset_all_modules(); DELAY_Ms(500); // 2. 检查所有模块版本号 for (uint8_t i = 0; i < HV_MODULE_COUNT; i++) { if (!check_module_version(i + 1)) { g_hv_sys_status.modules[i].is_faulty = true; hv_voltage_shutdown(); return HV_ERR_MODULE_FAULT; } } // 3. 逐个模块测试(输出50V,验证电压) for (uint8_t i = 0; i < HV_MODULE_COUNT; i++) { uint8_t module_id = i + 1; hv_module_status_t* module = &g_hv_sys_status.modules[i]; WriteAnalog_t* analog = get_write_analog_instance(module_id); DacIcDev_t* dac_dev = &xDacIcDev1 + i; if (analog == NULL || dac_dev == NULL) { hv_voltage_shutdown(); return HV_ERR_MODULE_INVALID; } // 关闭所有输出 for (uint8_t j = 0; j < HV_MODULE_COUNT; j++) { hv_set_s2_ex(j + 1, 0); hv_set_s1_ex(j + 1, 0); } DELAY_Ms(500); // 配置测试电压(50V) float test_vol = 50.0f; uint16_t dac_val = (uint16_t)(test_vol * DAC_VOLTAGE_TO_VALUE); dac_val = (dac_val > 4095) ? 4095 : dac_val; // 启用模块并发送DAC指令 hv_set_s1_ex(module_id, 1); analog->vInit(analog, dac_dev); analog->vSetA(analog, dac_val); DELAY_Ms(500); // 打开该模块的高压输出 hv_set_s2_ex(module_id, 1); DELAY_Ms(200); // 读取测试数据 uint16_t adc_module = hv_spi_adc_read(module_id, 1); // 模块输出电压 uint16_t adc_line = hv_spi_adc_read(module_id, 2); // 高压线电压 uint16_t adc_dac = hv_spi_adc_read(module_id, 6); // DAC反馈电压 float module_vol = adc_module * ADC_MODULE_VOLTAGE_COEF; float line_vol = adc_line * ADC_MODULE_VOLTAGE_COEF; float dac_vol = adc_dac * ADC_DAC_VOLTAGE_COEF; // 故障判断(按模块说明文档逻辑) bool module_fault = false; if (fabsf(module_vol - test_vol) > test_vol * 0.1f && fabsf(line_vol - test_vol) > test_vol * 0.1f) { if (line_vol < 100.0f) { module_fault = true; // 高压模块-高压输入错误 } else if (fabsf(dac_vol - (test_vol / DAC_VOLTAGE_TO_VALUE * 4095.0f / 5.0f)) > 1.0f) { module_fault = true; // 高压模块-ADC/DAC错误 } else if (line_vol > 100.0f && fabsf(dac_vol - (test_vol / DAC_VOLTAGE_TO_VALUE * 4095.0f / 5.0f)) <= 1.0f) { module_fault = true; // 高压模块-调压错误 } } // 读取版本号再次验证 if (!check_module_version(module_id)) { module_fault = true; } if (module_fault) { module->is_faulty = true; hv_set_s2_ex(module_id, 0); hv_set_s1_ex(module_id, 0); hv_voltage_shutdown(); return HV_ERR_MODULE_FAULT; } // 关闭当前模块测试 hv_set_s2_ex(module_id, 0); hv_set_s1_ex(module_id, 0); DELAY_Ms(100); } // 4. 测试通过,复位状态 reset_all_modules(); return HV_ERR_SUCCESS; } /***********************六、紧急停机 hv_voltage_shutdown******************************************* */ void hv_voltage_shutdown(void) { // 关闭所有高压输出和模块使能 for (uint8_t i = 0; i < HV_MODULE_COUNT; i++) { hv_set_s2_ex(i + 1, 0); hv_set_s1_ex(i + 1, 0); g_hv_sys_status.modules[i].is_enabled = false; g_hv_sys_status.modules[i].is_faulty = false; } // 复位系统状态 g_hv_sys_status.active_module_cnt = 0; g_hv_sys_status.total_target_voltage = 0.0f; g_hv_sys_status.total_actual_voltage = 0.0f; } // -------------------------- 静态函数实现 -------------------------- static WriteAnalog_t* get_write_analog_instance(uint8_t module_id) { switch (module_id) { case 1: return &xWriteAnalog1; case 2: return &xWriteAnalog2; case 3: return &xWriteAnalog3; case 4: return &xWriteAnalog4; case 5: return &xWriteAnalog5; default: return NULL; } } static bool check_module_version(uint8_t module_id) { // 读取ADC通道7 uint16_t adc_val = hv_spi_adc_read(module_id, 7); float version_vol = adc_val * ADC_VERSION_COEF; // 版本号有效范围:0.5V~2.5V if (version_vol >= 0.5f && version_vol <= 2.5f) { g_hv_sys_status.modules[module_id - 1].version_voltage = version_vol; return true; } return false; } static void reset_all_modules(void) { for (uint8_t i = 0; i < HV_MODULE_COUNT; i++) { hv_module_status_t* module = &g_hv_sys_status.modules[i]; module->is_enabled = false; module->target_voltage = 0.0f; module->actual_voltage = 0.0f; module->dac_value = 0; module->is_faulty = false; module->version_voltage = 0.0f; } g_hv_sys_status.active_module_cnt = 0; g_hv_sys_status.total_target_voltage = 0.0f; g_hv_sys_status.total_actual_voltage = 0.0f; } // -------------------------- 底层硬件接口实现 -------------------------- /************1. 控制模块使能引脚 S1_EX hv_set_s1_ex*************** */ void hv_set_s1_ex(uint8_t module_id, uint8_t enable) { // 校验模块ID(1~5) if (module_id < 1 || module_id > HV_MODULE_COUNT) return; // 使用静态数组映射模块ID到IO引脚 static const io_ctrl_id_et s1_pins[HV_MODULE_COUNT] = { IO_CTRL_HV_S1_1, // 模块1 IO_CTRL_HV_S1_2, // 模块2 IO_CTRL_HV_S1_3, // 模块3 IO_CTRL_HV_S1_4, // 模块4 IO_CTRL_HV_S1_5 // 模块5 }; io_ctrl_id_et io_id = s1_pins[module_id - 1]; static bool s1_inited[HV_MODULE_COUNT] = {false}; if (!s1_inited[module_id - 1]) { io_ctrl.init(io_id, IO_MODE_OUTPUT_PP); // 推挽输出 s1_inited[module_id - 1] = true; } io_ctrl.set(io_id, enable ? IO_SET : IO_RESET); } /************2. 读取 ADC 值 hv_spi_adc_read********************** */ uint16_t hv_spi_adc_read(uint8_t module_id, uint8_t channel) { // 1. 参数合法性校验 if (module_id < 1 || module_id > HV_MODULE_COUNT || channel < 1 || channel > 7) { return 0; } // 2. 初始化ADC片选引脚 io_ctrl_id_et cs_pin; switch(module_id) { case 1: cs_pin = IO_CTRL_HV_ADC_DECODE0; break; case 2: cs_pin = IO_CTRL_HV_ADC_DECODE1; break; case 3: cs_pin = IO_CTRL_HV_ADC_DECODE2; break; case 4: cs_pin = IO_CTRL_HV_ADC_DECODE0; break; case 5: cs_pin = IO_CTRL_HV_ADC_DECODE1; break; default: return 0; } io_ctrl.init(cs_pin, IO_MODE_OUTPUT_PP); io_ctrl.set(cs_pin, IO_SET); // 初始高电平,未选中 // 3. 拉低片选,选中ADC io_ctrl.set(cs_pin, IO_RESET); //ls_sys.DELAY_Ms(1); // 片选稳定延时 // 4. 构建SPI命令 uint8_t cmd = ( (channel - 1) << 4 ) | 0x0C; // 通道选择+配置位 uint8_t rx_buf[2] = {0}; // 5. SPI收发数据(基于ls_spi库,同步发送命令并接收数据) SPI_SendData(SPI1, cmd); while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT)); // 等待发送完成 while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_RXAVL)); // 等待接收完成 rx_buf[0] = SPI_ReceiveData(SPI1); // 接收高8位数据 SPI_SendData(SPI1, 0x00); // 占位字节,触发第二次接收 while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT)); while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_RXAVL)); rx_buf[1] = SPI_ReceiveData(SPI1); // 接收低8位数据 // 6. 拉高片选,结束通信 io_ctrl.set(cs_pin, IO_SET); // 7. 转换为12位ADC值(TLA2518输出16位,取高12位) return ( (rx_buf[0] << 8) | rx_buf[1] ) >> 4; } /*********3. 控制高压输出引脚 hv_set_s2_ex************** */ void hv_set_s2_ex(uint8_t module_id, uint8_t enable) { // 校验模块ID(1~5) if (module_id < 1 || module_id > HV_MODULE_COUNT) return; static bool s2_inited = false; if (!s2_inited) { // 初始化S2解码引脚为推挽输出 io_ctrl.init(IO_CTRL_HV_S2_DECODE0, IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_S2_DECODE1, IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_S2_DECODE2, IO_MODE_OUTPUT_PP); s2_inited = true; } // 仅允许一个模块使能:先关闭所有,再打开目标 if (enable) { io_ctrl.set(IO_CTRL_HV_S2_DECODE0, (module_id & 0x01) ? IO_SET : IO_RESET); io_ctrl.set(IO_CTRL_HV_S2_DECODE1, (module_id & 0x02) ? IO_SET : IO_RESET); io_ctrl.set(IO_CTRL_HV_S2_DECODE2, (module_id & 0x04) ? IO_SET : IO_RESET); } else { // 禁用时关闭所有解码引脚 io_ctrl.set(IO_CTRL_HV_S2_DECODE0, IO_RESET); io_ctrl.set(IO_CTRL_HV_S2_DECODE1, IO_RESET); io_ctrl.set(IO_CTRL_HV_S2_DECODE2, IO_RESET); } } /************4. 延时函数实现(调用delay.h中的底层延时)*************** */ void DELAY_Ms(uint32_t ms) { ls_sys.delay_ms(ms); } /************5. SPI DAC全局初始化(复用write_analog.c逻辑,补全时钟使能)*************** */ void spi_dac_global_init(void) { GPIO_InitTypeDef GPIO_InitStruct; SPI_InitTypeDef SPI_InitStruct; // 1. 使能GPIO和SPI时钟(关键修复:之前注释导致外设无法工作) RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE); // PB口时钟(SPI引脚) RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOC, ENABLE); // PC口时钟(CS引脚) RCC_APB2PeriphClockCmd(RCC_APB2ENR_SPI1, ENABLE); // SPI1时钟 // 2. GPIO引脚复用配置(PB3=SCK, PB4=MISO, PB5=MOSI) GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_0); GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_0); GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_0); // 3. CS引脚配置(PC6:推挽输出) GPIO_StructInit(&GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC, &GPIO_InitStruct); GPIO_SetBits(GPIOC, GPIO_Pin_6); // 初始高电平,未选中 // 4. SPI引脚配置(SCK/MOSI推挽输出,MISO浮空输入) GPIO_StructInit(&GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_5; // SCK+MOSI GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOB, &GPIO_InitStruct); GPIO_StructInit(&GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4; // MISO GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_FLOATING; GPIO_Init(GPIOB, &GPIO_InitStruct); // 5. SPI参数配置(主机模式,8位数据,CPOL低,CPHA第2沿) SPI_DeInit(SPI1); SPI_StructInit(&SPI_InitStruct); SPI_InitStruct.SPI_Mode = SPI_Mode_Master; SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; SPI_InitStruct.SPI_DataWidth = 8; SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge; SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB; SPI_Init(SPI1, &SPI_InitStruct); // 6. 启用SPI收发双向模式 SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Rx); SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Tx); SPI_Cmd(SPI1, ENABLE); } #ifndef HV_VOLTAGE_CTRL_H #define HV_VOLTAGE_CTRL_H #include <stdint.h> #include <stdbool.h> #include <stddef.h> #include "write_analog.h" // -------------------------- 硬件参数宏定义 -------------------------- #define HV_MODULE_COUNT 5 // 总高压模块数 #define HV_MODULE_MIN_VOLTAGE 10.0f // 单个模块最低输出电压(V) #define HV_MODULE_MAX_VOLTAGE 100.0f // 单个模块最高输出电压(V) #define HV_TOTAL_MAX_VOLTAGE (HV_MODULE_COUNT * HV_MODULE_MAX_VOLTAGE) // 总最高电压(500V) // DAC/ADC系数(来自高压电源模块说明) #define DAC_VOLTAGE_TO_VALUE 33.42857142857f // DAC值 = 模块输出电压 × 该系数 #define ADC_MODULE_VOLTAGE_COEF 0.12332112332f // ADC通道1/2:电压 = ADC值 × 该系数 #define ADC_DAC_VOLTAGE_COEF (5.0f / 4095.0f) // ADC通道6:DAC反馈电压系数(5V参考/12位) #define ADC_VERSION_COEF (5.0f / 4095.0f) // ADC通道7:版本号电压系数 // 错误码定义 typedef enum { HV_ERR_SUCCESS = 0, // 成功 HV_ERR_VOLTAGE_LOW, // 电压低于最小值 HV_ERR_VOLTAGE_HIGH, // 电压高于最大值 HV_ERR_MODULE_INVALID, // 模块配置无效 HV_ERR_SPI_FAILED, // SPI通信失败 HV_ERR_ADC_READ_FAILED, // ADC读取失败 HV_ERR_MODULE_FAULT // 模块故障 } hv_error_t; // 单个模块状态结构体 typedef struct { bool is_enabled; // 是否启用 float target_voltage; // 目标电压(V) float actual_voltage; // 实际电压(V) uint16_t dac_value; // DAC设置值 bool is_faulty; // 是否故障 float version_voltage; // 版本号电压(V) } hv_module_status_t; // 系统整体状态结构体 typedef struct { hv_module_status_t modules[HV_MODULE_COUNT]; // 各模块状态 uint8_t active_module_cnt; // 活跃模块数 float total_target_voltage; // 总目标电压 float total_actual_voltage; // 总实际电压 } hv_system_status_t; // -------------------------- 外部接口声明 -------------------------- // S1_EX:模块使能(1=使能,0=禁用) void hv_set_s1_ex(uint8_t module_id, uint8_t enable); // S2_EX:高压输出使能(1=有效,0=无效;仅允许一个模块有效!) void hv_set_s2_ex(uint8_t module_id, uint8_t enable); // ADC读取(module_id:1~5;channel:1~7;返回ADC原始值) uint16_t hv_spi_adc_read(uint8_t module_id, uint8_t channel); // 延时函数(ms) void DELAY_Ms(uint32_t ms); // SPI DAC全局初始化 void spi_dac_global_init(void); // -------------------------- 高压控制核心接口 -------------------------- /** * @brief 高压系统初始化 * @param 无 * @return hv_error_t:错误码 */ hv_error_t hv_voltage_init(void); /** * @brief 设置总目标电压 * @param vol:总目标电压(V),范围:10V ~ 500V * @return hv_error_t:错误码 */ hv_error_t hv_set_voltage(float vol); /** * @brief 读取总实际电压 * @param actual_vol:输出参数,总实际电压(V) * @return hv_error_t:错误码 */ hv_error_t hv_read_total_voltage(float* actual_vol); /** * @brief 读取系统状态 * @param status:输出参数,系统状态 * @return hv_error_t:错误码 */ hv_error_t hv_get_system_status(hv_system_status_t* status); /** * @brief 高压系统自检 * @param 无 * @return hv_error_t:错误码(HV_ERR_SUCCESS=自检通过) */ hv_error_t hv_voltage_self_test(void); /** * @brief 关闭高压系统(紧急停机) * @param 无 * @return 无 */ void hv_voltage_shutdown(void); /** * @brief 测试函数:第一个模块输出50V * @param 无 * @return hv_error_t:错误码 */ hv_error_t hv_test_module1_output_50v(void); #endif // HV_VOLTAGE_CTRL_H #include <stdio.h> #include "ls_io_ctrl.h" #include "ls_system.h" #include "ls_uart0.h" #include "ls_spi.h" #include "sys_config.h" #include "io_comm.h" // IOͨ��Э��ͷ�ļ� #include "led.h" #include "task.h" //#include "ad5322.h" #include "tla2518_A.h" #include "write_analog.h" #include "delay.h" #include "hv_voltage_ctrl.h" #include "mm32_device.h" #define LOG_TAG "main.c" #define LOG_LEVEL LOG_LEVEL_VERBOSE #include "logger.h" //���ṹ�庯��ָ��ת��Ϊֱ�Ӻ������� void io_ctrl_init(io_ctrl_id_et io, io_ctrl_mode_et mode) { io_ctrl.init(io, mode); // ����GPIO��ʼ������ } void io_ctrl_set(io_ctrl_id_et io, mfU16_t val) { io_ctrl.set(io, val); // ����GPIO������? } io_ctrl_level_et io_ctrl_get(io_ctrl_id_et id) { return (io_ctrl_level_et)io_ctrl.get(id); // ��ȡGPIO������? } static void drv_port_init(void) { /***************PA*********/ io_ctrl.init(IO_CTRL_CURRENT_DECODE_0, IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_CURRENT_DECODE_1, IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_CURRENT_DECODE_2, IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_SELF_CHECK_CURRENT,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_STATE_LED4,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_LED,IO_MODE_OUTPUT_PP); io_ctrl.set(IO_CTRL_SELF_CHECK_CURRENT, IO_SET);// io_ctrl.set(IO_CTRL_CURRENT_DECODE_0, IO_SET); io_ctrl.set(IO_CTRL_CURRENT_DECODE_1,IO_SET); io_ctrl.set(IO_CTRL_CURRENT_DECODE_2, IO_SET); io_ctrl.set(IO_CTRL_STATE_LED4,IO_SET); io_ctrl.set(IO_CTRL_LED,IO_SET); /***********PB***********/ io_ctrl.init(IO_CTRL_STATE_LED3,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_STATE_LED2,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_STATE_LED1,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_DAC_DECODE0,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_DAC_DECODE1,IO_MODE_OUTPUT_PP); io_ctrl.set(IO_CTRL_STATE_LED3, IO_SET); io_ctrl.set(IO_CTRL_STATE_LED2, IO_SET); io_ctrl.set(IO_CTRL_STATE_LED1,IO_SET); io_ctrl.set(IO_CTRL_HV_DAC_DECODE0,IO_SET); io_ctrl.set(IO_CTRL_HV_DAC_DECODE1,IO_SET); io_ctrl.init(IO_CTRL_HV_DAC_DECODE2,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_ADC_DECODE0,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_ADC_DECODE1,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_ADC_DECODE2,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_S2_DECODE0,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_S2_DECODE1,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_S2_DECODE2,IO_MODE_OUTPUT_PP); io_ctrl.set(IO_CTRL_HV_DAC_DECODE2, IO_SET); io_ctrl.set(IO_CTRL_HV_ADC_DECODE0, IO_SET); io_ctrl.set(IO_CTRL_HV_ADC_DECODE1,IO_SET); io_ctrl.set(IO_CTRL_HV_ADC_DECODE2,IO_SET); io_ctrl.set(IO_CTRL_HV_S2_DECODE0,IO_SET); io_ctrl.set(IO_CTRL_HV_S2_DECODE1,IO_SET); io_ctrl.set(IO_CTRL_HV_S2_DECODE2, IO_SET); /****PC****/ io_ctrl.init(IO_CTRL_HV_LEVEL,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_LV_LEVEL1,IO_MODE_OUTPUT_PP); //10V io_ctrl.init(IO_CTRL_LV_LEVEL2,IO_MODE_OUTPUT_PP); //24V io_ctrl.init(IO_CTRL_LV_LEVEL3,IO_MODE_OUTPUT_PP); //48V io_ctrl.init(IO_CTRL_HV_S1_1,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_S1_2,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_S1_3,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_S1_4,IO_MODE_OUTPUT_PP); io_ctrl.init(IO_CTRL_HV_S1_5,IO_MODE_OUTPUT_PP); io_ctrl.set(IO_CTRL_HV_LEVEL,IO_RESET);// io_ctrl.set(IO_CTRL_LV_LEVEL1,IO_SET); io_ctrl.set(IO_CTRL_LV_LEVEL2,IO_SET); io_ctrl.set(IO_CTRL_LV_LEVEL3,IO_RESET); io_ctrl.set(IO_CTRL_HV_S1_1,IO_SET); io_ctrl.set(IO_CTRL_HV_S1_2,IO_SET); io_ctrl.set(IO_CTRL_HV_S1_3,IO_SET); io_ctrl.set(IO_CTRL_HV_S1_4,IO_SET); io_ctrl.set(IO_CTRL_HV_S1_5,IO_SET); } static void bsp_init(void) { ls_sys.sys_rcu_init(); ls_sys.systick_init(); uart0.init(); drv_port_init(); io_comm.init(); led_init(); hv_voltage_init(); tla2518_A.init(); // ad5322.init(); xWriteAnalog1.vInit(&xWriteAnalog1, &xDacIcDev1); xWriteAnalog2.vInit(&xWriteAnalog2, &xDacIcDev2); xWriteAnalog3.vInit(&xWriteAnalog3, &xDacIcDev3); xWriteAnalog4.vInit(&xWriteAnalog4, &xDacIcDev4); xWriteAnalog5.vInit(&xWriteAnalog5, &xDacIcDev5); uart0.send_bytes((mfU8_t *)VERSION_NAME, VERSION_SIZE); LOG_I("Building at %s %s",__DATE__,__TIME__); LOG_I("SystemCoreClock : %d",ls_sys.system_clock); } int main(void) { bsp_init(); LOG_I("System device init ok!"); // 调用测试函数,输出50V hv_error_t ret = hv_test_module1_output_50v(); if (ret == HV_ERR_SUCCESS) { printf("Output 50V success!\n"); } else { // 输出失败,处理错误(比如打印错误码) printf("Output 50V failed, error code: %d\n", ret); } while(1) { // 循环监测电压(可选) float actual_vol; hv_read_total_voltage(&actual_vol); // 3. 中文替换为英文 printf("Current output voltage: %.2fV\n", actual_vol); DELAY_Ms(1000); } } /* int main(void) { bsp_init(); LOG_I("System device init ok!"); task_start(); return 0; } */ /* int main(void) { bsp_init(); LOG_I("System device init ok!"); // 注释原任务启动函数,改为死循�?实现电压切换 // task_start(); while(1) { // 输出48V:置�?48V对应控制引脚 io_ctrl.set(IO_CTRL_LV_LEVEL3, IO_SET); ls_sys.delay_ms(50); // 延时50ms // 输出0V:拉�?48V对应控制引脚(关�?48V输出�? io_ctrl.set(IO_CTRL_LV_LEVEL3, IO_RESET); ls_sys.delay_ms(50); // 延时50ms } } */ 现在可以了吗,能不能保证只输出50V
11-28
### UVM中 `repeat(p_cfg.wdt_cnt) @vif.cb_drv` 的含义 在UVM(Universal Verification Methodology)中,`repeat(p_cfg.wdt_cnt) @vif.cb_drv` 是一种用于驱动信号的语法结构,通常出现在基于接口的验证环境中。以下是对其组成部分的详细解释: 1. **`repeat(p_cfg.wdt_cnt)`** - 这里的 `repeat` 是 SystemVerilog 中的关键字,表示重复执行某个操作或等待条件[^1]。 - `p_cfg.wdt_cnt` 是一个变量,通常定义在配置类(configuration class)中,表示需要重复的次数。例如,`wdt_cnt` 可能是看门狗定时器(watchdog timer)的计数值。 - 整体含义:`repeat(p_cfg.wdt_cnt)` 表示重复执行后面的语句 `p_cfg.wdt_cnt` 次。 2. **`@vif.cb_drv`** - `vif` 是虚拟接口(virtual interface)的缩写,用于在测试平台(testbench)和设计(DUT, Design Under Test)之间传递信号[^2]。 - `cb_drv` 是接口中的一个时钟边界(clocking block),通常用于同步信号驱动或采样。它确保所有操作都在指定的时钟边沿上进行。 - 整体含义:`@vif.cb_drv` 表示等待一次 `cb_drv` 时钟边沿的到来。 3. **组合含义** - `repeat(p_cfg.wdt_cnt) @vif.cb_drv` 表示等待 `p_cfg.wdt_cnt` 次 `cb_drv` 时钟边沿的到来。这通常用于模拟某种周期性事件的发生,例如看门狗定时器的超时周期[^3]。 ### 示例代码 以下是一个简单的代码示例,展示如何使用 `repeat` 和 `@vif.cb_drv`: ```systemverilog class my_driver extends uvm_driver #(my_transaction); virtual my_if vif; // 虚拟接口 config_class p_cfg; // 配置类 task run_phase(uvm_phase phase); repeat(p_cfg.wdt_cnt) begin @(vif.cb_drv); // 等待时钟边沿 // 在此处执行信号驱动或其他操作 end endtask: run_phase endclass: my_driver ``` ### 注意事项 - `p_cfg.wdt_cnt` 的值必须在配置阶段正确设置,否则可能导致行为不符合预期。 - 如果 `vif` 或 `cb_drv` 未正确连接到实际接口,可能会导致仿真错误或死锁。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

静思心远

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值