ADDA数模转换(PCF8591)

ADDA转换概念:
是指模/数转换器或者模拟/数字转换器 。
是指将连续变量的模拟信号转换为离散的数字信号的器件。
典型的模拟数字转换器将模拟信号转换为表示一定比例电压值的数字信号。
PCF8591
	PCF8591是一种具有I2C总线接口的8位A/D,D/A转换芯片,在于
CPU的信息传输过程中仅靠时钟线SCL与数据线SDA就可以实现 。在
PCF8591的器件上输入输出的地址、控制和数据信号都是通过双向总线以
串行的方式进行传输 。PCF8591的功能包括多路模拟输入、内置跟踪保
持、8-bit模数转换和8-bit数模转换 。PCF8591的最大转换速率由I2C
总线的最大速率决定。
PCF8591电路图

在这里插入图片描述

PCF8591具有4个模拟输入(AIN0~AIN3)、1个模拟输出(AOUT)和1个串行I²C总线接口(SDA、SCL)。 
PCF8591的3个地址引脚A0, A1和A2可用于硬件地址编程,允许在同个I2C总线上接入8个PCF8591器件,而无需额外的硬件。
在PCF8591器件上输入输出的地址、控制和数据信号都是通过双线双向I2C总线以串行的方式进行传输。 
OSC:外部时钟输入端,内部时钟 
EXT:内部、外部时钟选择线,使用内部时钟时 EXT 接地。 
VDD、VSS:电源端。 
AGND:模拟信号地。 
VREF:基准电源端

AD源码

int main(void)
{ 
	u16 adcx;
	float temp;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	delay_init(168);    //初始化延时函数
	uart_init(115200); //初始化串口波特率为115200
	Adc_Init();         //初始化ADC

	while(1)
	{ 
	adcx=Get_Adc_Average(ADC_Channel_5,20);//获取通道5的转换值,20次取平均
	temp=(float)adcx*(3.3/4096);          //获取计算后的带小数的实际电压值,比如3.1111
	adcx=temp;                            //赋值整数部分给adcx变量,因为adcx为u16整形
	temp-=adcx;                           //把已经显示的整数部分去掉,留下小数部分,比如3.1111-3=0.1111
	temp*=1000;                           //小数部分乘以1000,例如:0.1111就转换为111.1,相当于保留三位小数。
	delay_ms(250); 
	}
}
#include "adc.h"
#include "delay.h" 

//初始化ADC                  
void  Adc_Init(void)
{    
	GPIO_InitTypeDef  GPIO_InitStructure;
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	ADC_InitTypeDef  ADC_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能ADC1时钟

	//先初始化ADC1通道5 IO口
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//PA5 通道5
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//不带上下拉
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化  
	
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);   //ADC1复位
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE); //复位结束  

	ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
	ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;//两个采样阶段之间的延迟5个时钟
	ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //DMA失能
	ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//预分频4分频。ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36Mhz 
	ADC_CommonInit(&ADC_CommonInitStructure);//初始化
	
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12位模式
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描模式 
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//关闭连续转换
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止触发检测,使用软件触发
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐 
	ADC_InitStructure.ADC_NbrOfConversion = 1;//1个转换在规则序列中 也就是只转换规则序列1 
	ADC_Init(ADC1, &ADC_InitStructure);//ADC初始化
}
	
//获得ADC值
//ch: @ref ADC_channels 
//通道值 0~16取值范围为:ADC_Channel_0~ADC_Channel_16
//返回值:转换结果
u16 Get_Adc(u8 ch) 
{
	//设置指定ADC的规则组通道,一个序列,采样时间
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_480Cycles ); //ADC1,ADC通道,480个周期,提高采样时间可以提高精确度       
	ADC_SoftwareStartConv(ADC1);  //使能指定的ADC1的软件转换启动功能 
	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
	return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果
}

//获取通道ch的转换值,取times次,然后平均 
//ch:通道编号
//times:获取次数
//返回值:通道ch的times次转换结果平均值

u16 Get_Adc_Average(u8 ch,u8 times)
{
	u32 temp_val=0;
	u8 t;
	for(t=0;t<times;t++)
	{
		temp_val+=Get_Adc(ch);
		delay_ms(5);
	}
	return temp_val/times;
} 

DA源码

int main(void)
{ 
	u16 adcx;
	float temp;
	u8 t=0;  
	u16 dacval=0;
	u8 key; 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	delay_init(168);      //初始化延时函数
	uart_init(115200);  //初始化串口波特率为115200
	Adc_Init();     //adc初始化
	KEY_Init();     //按键初始化
	Dac1_Init();     //DAC通道1初始化
	DAC_SetChannel1Data(DAC_Align_12b_R,dacval);//初始值为0 
	
	while(1)
	{
		t++;
		key=KEY_Scan(0);     
		if(key==WKUP_PRES)
		{   
			if(dacval<4000)dacval+=200;
			DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值
		}
		else if(key==2) 
		{
			if(dacval>200)dacval-=200;
			else dacval=0;
			DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值
		}  
		if(t==10||key==KEY1_PRES||key==WKUP_PRES)  //WKUP/KEY1按下了,或者定时时间到了
		{   
 			adcx=DAC_GetDataOutputValue(DAC_Channel_1);//读取前面设置DAC的值
			temp=(float)adcx*(3.3/4096);            //得到DAC电压值
			adcx=temp;
			temp-=adcx;
			temp*=1000;
			adcx=Get_Adc_Average(ADC_Channel_5,10);  //得到ADC转换值   
			temp=(float)adcx*(3.3/4096);           //得到ADC电压值
			adcx=temp;
			temp-=adcx;
			temp*=1000;    
			t=0;
		}     
	delay_ms(10);  
	} 
}
#include "dac.h"

//DAC通道1输出初始化
void Dac1_Init(void)
{  
	GPIO_InitTypeDef  GPIO_InitStructure;
	DAC_InitTypeDef DAC_InitType;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);//使能DAC时钟
	  
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;//下拉
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
	
	DAC_InitType.DAC_Trigger=DAC_Trigger_None; //不使用触发功能 TEN1=0
	DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
	DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置
	DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ; //DAC1输出缓存关闭 BOFF1=1
	DAC_Init(DAC_Channel_1,&DAC_InitType);  //初始化DAC通道1
	DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC通道1
  
	DAC_SetChannel1Data(DAC_Align_12b_R, 0);  //12位右对齐数据格式设置DAC值
}

//设置通道1输出电压
//vol:0~3300,代表0~3.3V
void Dac1_Set_Vol(u16 vol)
{
	double temp=vol;
	temp/=1000;
	temp=temp*4096/3.3;
	DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值
}
  • 9
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一份基于Adda系列PCF8591的驱动程序,带有详细的注释: ```c #include <linux/init.h> // 驱动程序的初始化 #include <linux/module.h> // 使用模块化的方式编写驱动程序 #include <linux/i2c.h> // 使用I2C的通信方式 #include <linux/i2c-dev.h> // 使用I2C设备驱动 #include <linux/fs.h> // 文件系统相关的函数 #include <linux/types.h> // 提供数据类型的定义 #include <linux/cdev.h> // 字符设备相关的函数 #include <asm/uaccess.h> // 提供用户空间和内核空间之间拷贝数据的函数 // 定义I2C设备的地址 #define PCF8591_ADDR 0x48 // 定义驱动程序所操作的设备名称 static const char* driver_name = "pcf8591"; // 定义驱动程序对应的字符设备 static struct cdev pcf8591_cdev; // 定义I2C设备 static struct i2c_client* pcf8591_client; // 驱动程序的文件打开函数 static int pcf8591_open(struct inode* inode, struct file* filp) { // 添加打开设备时的操作 return 0; // 返回0表示成功 } // 驱动程序的文件读取函数 static ssize_t pcf8591_read(struct file* filp, char __user* buf, size_t count, loff_t* f_pos) { // 添加读取设备数据的操作 return count; // 返回读取的字节数 } // 驱动程序的文件写入函数 static ssize_t pcf8591_write(struct file* filp, const char __user* buf, size_t count, loff_t* f_pos) { // 添加写入设备数据的操作 return count; // 返回写入的字节数 } // 驱动程序的文件关闭函数 int pcf8591_release(struct inode* inode, struct file* filp) { // 添加关闭设备时的操作 return 0; // 返回0表示成功 } // 驱动程序的文件操作结构体 static struct file_operations pcf8591_fops = { .owner = THIS_MODULE, .open = pcf8591_open, .read = pcf8591_read, .write = pcf8591_write, .release = pcf8591_release, }; // 驱动程序的初始化函数 static int pcf8591_init(void) { // 注册字符设备 int ret = register_chrdev_region(MKDEV(0, 0), 1, driver_name); if (ret) { printk(KERN_ALERT "Failed to register device\n"); return ret; } // 分配字符设备结构体 cdev_init(&pcf8591_cdev, &pcf8591_fops); ret = cdev_add(&pcf8591_cdev, MKDEV(0, 0), 1); if (ret) { printk(KERN_ALERT "Failed to add device\n"); unregister_chrdev_region(MKDEV(0, 0), 1); return ret; } // 获取并注册I2C设备 struct i2c_adapter* pcf8591_adapter = i2c_get_adapter(0); pcf8591_client = i2c_new_device(pcf8591_adapter, NULL); i2c_put_adapter(pcf8591_adapter); if (!pcf8591_client) { printk(KERN_ALERT "Failed to register I2C device\n"); cdev_del(&pcf8591_cdev); unregister_chrdev_region(MKDEV(0, 0), 1); return -1; } printk(KERN_ALERT "pcf8591 driver initialized\n"); return 0; } // 驱动程序的卸载函数 static void pcf8591_exit(void) { // 注销I2C设备 i2c_unregister_device(pcf8591_client); // 注销字符设备 cdev_del(&pcf8591_cdev); unregister_chrdev_region(MKDEV(0, 0), 1); printk(KERN_ALERT "pcf8591 driver exited\n"); } // 指定驱动程序的初始化和卸载函数 module_init(pcf8591_init); module_exit(pcf8591_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("Driver for adda PCF8591"); ``` 这份驱动程序使用了Linux内核提供的I2C和字符设备相关的函数,通过I2C通信方式与PCF8591芯片进行通信。驱动程序提供了打开、读取、写入和关闭设备的操作,并在初始化时注册了一个字符设备供用户空间进行访问。驱动程序的初始化函数和卸载函数在模块初始化和卸载时被调用,分别用来注册和注销设备。详细的注释说明了每个函数的功能和操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值