基于ZYNQ7100的AD7606电压实时监测系统,过压蜂鸣器报警,提供工程源码和技术支持

开发环境如下:
开发板:米联客ZYNQ7100,MZ7100FA开发板;
AD7606模块:米联客的AD7606,串行输出模式,这里只有通道1有输入,所以只需要输出通道1;
EDA:VIVADO2019.2;
硬件连接实物如图:
在这里插入图片描述
设计框图如下:
在这里插入图片描述
AD7606的FPGA采集部分请看我前面的文章https://blog.csdn.net/qq_41667729/article/details/124061910
不同的是,为了配合zynq使用,我把源码封装成了自定义IP,如下:
在这里插入图片描述
IP配置如下:
在这里插入图片描述
大概原理:
稳压电源输出一个电压到AD7606模块,zynq7100的PL采集数据,并做16位的并行输出;
调用一个AXI GPIO的IP,BANK1设置为输入,16位,用于连接PL采集到的6位的并行数据,BANK2设置为输出,1位,用于控制蜂鸣器,蜂鸣器是有源的,给高电平触发,AXI GPIO配置如下:
在这里插入图片描述
最后,导出bit,加载SDK,在SDK里做浮点运算,算出实时采集到的电压值,再做比较,若采集到的电压值大于阈值,则蜂鸣器响。
BD如下图:
在这里插入图片描述
AD7606输入电压值得算法如下:
在这里插入图片描述
我的采集用的是±10V模式,在verilog代码里有,如图:
在这里插入图片描述
AD7606模块使用的是内部参考电压2.5V,所以公式中的REF/2.5V=1;
所以,根据公式自然可以得出,VIN=CODE*10/32768;其中CODE就是采集到的通道1的16位采集数据;
SDK主函数如下:

int main()
{
    init_platform();
	u16 ad7606;
	float V;
	XGpioCfg = XGpio_LookupConfig(GPIO_BUZZER_DEVICE_ID);
	XGpio_CfgInitialize(&buzzer, XGpioCfg, XGpioCfg->BaseAddress);
	XGpio_SetDataDirection(&buzzer, XGPIO_BANK1, 1);	//in
	XGpio_SetDataDirection(&buzzer, XGPIO_BANK2, 0);	//out
	XGpio_DiscreteWrite(&buzzer, XGPIO_BANK2, 0);	//buzzer not work

	while(1){
		ad7606=XGpio_DiscreteRead(&buzzer, XGPIO_BANK1);
		V=(float)ad7606*10/32768;
		if(V>=6.2){	//threshold=6.2V
			XGpio_DiscreteWrite(&buzzer, XGPIO_BANK2, 1);	//buzzer not work
		}
		else XGpio_DiscreteWrite(&buzzer, XGPIO_BANK2, 0);	//buzzer not work
		//sleep(1);
		//printf("V=%f",V);
	}
    cleanup_platform();
    return 0;
}

我们来DEBUG一下看看效果:
先将电源输出设置为6.125,如下:
在这里插入图片描述
看看此时的采集到的值:
在这里插入图片描述
此时采集到的电压不足6.2V,再单步运行,程序跳到了蜂鸣器不工作的语句,如下:
在这里插入图片描述
现在把电源输出调到6.5246,如下:
在这里插入图片描述
再来看看DEBUG,
在这里插入图片描述
此时采集到的电压超过阈值6.2V,再单步运行,程序跳到了蜂鸣器工作的语句,如下:
在这里插入图片描述
注意事项:
1、AD7606采集的verilog代码,一定要认真读官方数据手册里面的几个时序图,特别是几个关键信号的持续时间,不然采集失败,不过还好,因为我已经帮你们做好了,工程拿去直接用就是,代码里也有注释,不过请原谅我数学老师教的英语注释;
2、电源输入时一定要注意电源地要和信号地共地,不然采集到的数据是乱的;
3、浮点运算时要把采集到的数据强制转换为浮点型,我不是专业搞软件的,最开始没注意,所以算出过总是没有小数点;

福利:工程代码的获取
代码太大,无法邮箱发送,以某度网盘链接方式发送,
工程源码下载链接:https://download.csdn.net/download/qq_41667729/87767253
网盘资料如下:
在这里插入图片描述

  • 5
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
首先,需要说明的是ZYNQ是一款SOC(System on Chip),它包含了ARM Cortex-A9处理器和FPGA,因此可以通过FPGA实现我们的PID控制算法,通过ARM Cortex-A9处理器控制AD7606AD9767芯片的数据采集和输出。 以下是一个基于ZYNQ的PID控制电压输出的程序框架: ``` // 引入头文件 #include <stdio.h> #include <stdlib.h> #include <math.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> // 定义寄存器地址 #define XADC_BASE_ADDR 0x40000000 #define XADC_CHAN_OFFSET 0x0 #define XADC_TEMP_OFFSET 0x1E0 #define GPIO_BASE_ADDR 0x41200000 #define GPIO_DATA_OFFSET 0x00 #define GPIO_TRI_OFFSET 0x04 #define PWM_BASE_ADDR 0x43C10000 #define PWM_CTRL_OFFSET 0x0 #define PWM_PERIOD_OFFSET 0x4 #define PWM_DUTY_OFFSET 0x8 // 定义PID控制器参数 float Kp = 0.0; float Ki = 0.0; float Kd = 0.0; float dt = 0.0; float setpoint = 0.0; float prev_error = 0.0; float integral = 0.0; // 定义PWM输出参数 float period = 0.0; float duty = 0.0; // 定义寄存器映射指针 volatile uint32_t *xadc; volatile uint32_t *gpio; volatile uint32_t *pwm; // 定义函数原型 void init(); void cleanup(); float read_adc(uint8_t ch); void set_pwm(float period, float duty); float pid_control(float input); int main(int argc, char **argv) { // 初始化 init(); // 主循环 while (1) { // 读取ADC值 float input = read_adc(0); // PID控制 float output = pid_control(input); // PWM输出 set_pwm(period, duty); } // 清理 cleanup(); return 0; } void init() { // 打开设备文件 int fd = open("/dev/mem", O_RDWR | O_SYNC); if (fd < 0) { perror("open"); exit(EXIT_FAILURE); } // 映射XADC寄存器 xadc = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, XADC_BASE_ADDR); if (xadc == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); } // 映射GPIO寄存器 gpio = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO_BASE_ADDR); if (gpio == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); } // 映射PWM寄存器 pwm = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, PWM_BASE_ADDR); if (pwm == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); } // 初始化GPIO *(gpio + GPIO_TRI_OFFSET) = 0x0; // 初始化PWM *(pwm + PWM_CTRL_OFFSET) = 0x0; // 初始化PID控制器 Kp = 0.0; Ki = 0.0; Kd = 0.0; dt = 0.0; setpoint = 0.0; prev_error = 0.0; integral = 0.0; } void cleanup() { // 取消映射 munmap((void *)xadc, 0x1000); munmap((void *)gpio, 0x1000); munmap((void *)pwm, 0x1000); } float read_adc(uint8_t ch) { // 读取ADC值 uint32_t reg = *(xadc + XADC_CHAN_OFFSET + ch); // 转换为电压值 float voltage = (float)reg / 4096.0 * 3.3; return voltage; } void set_pwm(float period, float duty) { // 设置PWM周期 *(pwm + PWM_PERIOD_OFFSET) = (uint32_t)(period / 10.0 * 100000000.0); // 设置PWM占空比 *(pwm + PWM_DUTY_OFFSET) = (uint32_t)(duty / period * 100.0 * 65535.0 / 100.0); // 启动PWM *(pwm + PWM_CTRL_OFFSET) = 0x1; } float pid_control(float input) { // 计算误差 float error = setpoint - input; // 计算积分项 integral += error * dt; // 计算微分项 float derivative = (error - prev_error) / dt; // 计算输出 float output = Kp * error + Ki * integral + Kd * derivative; // 更新误差 prev_error = error; return output; } ``` 以上代码是一个基本的框架,需要根据实际情况进行调整和完善。具体步骤如下: 1. 引入头文件:包括需要用到的标准头文件和自定义的头文件。 2. 定义寄存器地址:需要定义AD7606AD9767、GPIO和PWM模块的寄存器地址。 3. 定义PID控制器参数:定义需要用到的PID控制器参数,如比例系数Kp、积分系数Ki、微分系数Kd、采样时间dt、设定值setpoint、前一次误差prev_error和积分项integral等。 4. 定义PWM输出参数:定义需要用到的PWM输出参数,如周期period和占空比duty等。 5. 定义寄存器映射指针:定义需要用到的寄存器映射指针,包括AD7606AD9767、GPIO和PWM模块的寄存器指针。 6. 定义函数原型:定义需要用到的函数原型,包括初始化函数init()、清理函数cleanup()、读取ADC值函数read_adc()、设置PWM输出函数set_pwm()和PID控制函数pid_control()等。 7. 初始化:在init()函数中,需要打开设备文件/dev/mem,然后映射需要用到的寄存器。 8. 读取ADC值:在read_adc()函数中,需要读取AD7606芯片的ADC值,然后将其转换为电压值。 9. 设置PWM输出:在set_pwm()函数中,需要设置PWM的周期和占空比,并启动PWM输出。 10. PID控制:在pid_control()函数中,需要计算误差、积分项、微分项和输出值,并更新前一次误差和积分项。 11. 主循环:在主循环中,需要不断读取ADC值、进行PID控制和PWM输出。 12. 清理:在cleanup()函数中,需要取消寄存器的映射。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

9527华安

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

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

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

打赏作者

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

抵扣说明:

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

余额充值