STM32F103C8T6与MCP4725外部DAC的源码及接线指南

关于stm32f103c8t6的DAC

        STM32F103C8T6最小系统板是大家很常用的一款单片机,它内部有多个ADC模数转换通道,但并没有DAC数模转换功能,当需要进行数字量转换为模拟量时就需要借助外部DAC。    

关于MCP4725

        MCP4725是具有非易失性存储器的单通道12位缓冲电压输出DAC。用户可将配置寄存器位(2位)和DAC输入数据(12位)存储 到非易失性EEPROM (14位)存储器中。通过设置配置寄存器位可以把DAC配置成正常模式或节省功耗的关断模式。器件可以使用2线I2C兼容串行接口,且由电压范围为2.7V至5.5V的单电源供电。

         通过I2C总线外接MCP4725模块,从而弥补了STM32F103C8T6无DAC的不足。并且当用5V单电源供电时,其DAC通道可以输出5V的电压。

接线图

      

 VCC接3.3V,

GND接GND,

SCL接PB6,

SDA接PB7,

OUT,GND测试引脚

效果展示: 

电压误差值0.01V

 问题解答:

        如果你接线正确并运行代码后,用万用表测的电压为供电电压的一半,与实际应该输出的电压值不相符,修改MCP4725.C代码中的地址

        如果ADDR接VCC地址为:0xc2

        如果ADDR接GND地址为:0xc0

我使用的是这款,所以代码中的地址为0XC0

 代码:

I2C.C代码:
#include "stm32f10x.h"                  // Device header
#include "myIIC.h"
#include "delay.h"

/*引脚配置*/
#define MCP4725_W_SCL(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_6, (BitAction)(x))
#define MCP4725_W_SDA(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_7, (BitAction)(x))
#define MCP4725_W_SDAIN			GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7)


//初始化IIC
void IIC_Init(void)
{					     
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );	//使能GPIOB时钟
	   
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;         //PB6 ->SCL;  PB7->SDA
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); 	//PB6,PB7 输出高,因为IIC空闲状态都是高电平
}

//SDA设置为输入
void SDA_IN (void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );	
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

//SDA设置为输出
void SDA_OUT(void)
{ 
	GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );	
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//产生IIC起始信号
void IIC_Start(void)
{
	SDA_OUT();     //sda线设置为输出
	MCP4725_W_SDA(1);	  	  
	MCP4725_W_SCL(1);
	Delay_us(10);
 	MCP4725_W_SDA(0);     //START:when CLK is high,DATA change form high to low 
	Delay_us(10);
	MCP4725_W_SCL(0);    //钳住I2C总线,准备发送或接收数据 
}	  
//产生IIC停止信号
void IIC_Stop(void)
{
	SDA_OUT();//sda线输出
	MCP4725_W_SCL(0);
	MCP4725_W_SDA(0);//STOP:when CLK is high DATA change form low to high
 	Delay_us(10);
	MCP4725_W_SCL(1);
	MCP4725_W_SDA(1);//发送I2C总线结束信号
	Delay_us(10);							   	
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	SDA_IN();      //SDA设置为输入  
	MCP4725_W_SDA(1);
	Delay_us(2);	   
	MCP4725_W_SCL(1);
	Delay_us(2);	 
	while(MCP4725_W_SDAIN)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	MCP4725_W_SCL(0);//时钟输出0 	   
	return 0;  
} 
//产生ACK应答
void IIC_Ack(void)
{
	MCP4725_W_SCL(0);
	SDA_OUT();
	MCP4725_W_SDA(0);
	Delay_us(5);
	MCP4725_W_SCL(1);
	Delay_us(5);
	MCP4725_W_SCL(0);
}
//不产生ACK应答		    
void IIC_NAck(void)
{
	MCP4725_W_SCL(0);
	SDA_OUT();
	MCP4725_W_SDA(1);
	Delay_us(5);
	MCP4725_W_SCL(1);
	Delay_us(5);
	MCP4725_W_SCL(0);
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
	SDA_OUT(); 	    
	MCP4725_W_SCL(0);//拉低时钟开始数据传输
    for(t=0;t<8;t++)    //开始准备信号线
    {              
		if((txd&0x80)>>7)
			MCP4725_W_SDA(1);
		else
			MCP4725_W_SDA(0);
		txd<<=1; 	  
		Delay_us(5);   //对TEA5767这三个延时都是必须的
		MCP4725_W_SCL(1);
		Delay_us(5); 
		MCP4725_W_SCL(0);
		Delay_us(5);
    }	 
} 	    
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        MCP4725_W_SCL(0);
        Delay_us(5);
		MCP4725_W_SCL(1);
        receive<<=1;
        if(MCP4725_W_SDAIN)
		{receive++;  }
		Delay_us(4); 
    }					 
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}
I2C.h
#ifndef __MYIIC_H
#define __MYIIC_H

//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口				 
void IIC_Start(void);				//发送IIC开始信号
void IIC_Stop(void);	  			//发送IIC停止信号
void IIC_Send_Byte(u8 txd);			//IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); 				//IIC等待ACK信号
void IIC_Ack(void);			        //IIC发送ACK信号
void IIC_NAck(void);				//IIC不发送ACK信号

void SDA_IN(void);
void SDA_OUT(void);

void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);	  
#endif
MCP4725.C代码:
#include "stm32f10x.h"                  // Device header

#include "MCP4725.h" 
#include "delay.h"


//初始化IIC接口
void MCP4725_Init(void)
{
	IIC_Init();
}

//使用快速模式写命令写DAC寄存器
void MCP4725_WriteData_Voltage(u16 Vout)   //电压单位mV
{
	u8 temp;
	u16 Dn;
	Dn = ( 4096 * Vout) / VREF_5V; //这里的VREF_5V宏定义为5000
	temp = (0x0F00 & Dn) >> 8;  //12位数据。0000XXXX XXXXXXXX 
	IIC_Start();
	IIC_Send_Byte(0XC0);      //器件寻址,器件代吗:1100; 地址位A2,A1,A0为 0 , 0 , 1;-> 1100 0010
    //这个地址0XC0或0XC1,根据自己购买的模块决定
    IIC_Wait_Ack();	 
    IIC_Send_Byte(temp); 	  //将高8位送到DAC寄存器
    IIC_Wait_Ack();	 
    IIC_Send_Byte(Dn);        //将低8位送到DAC寄存器
	IIC_Wait_Ack();	
    IIC_Stop();//产生一个停止条件  	
	Delay_ms(10);	
}
 
void MCP4725_WriteData_Digital(u16 data)   //12位数字量
{
    u8 data_H=0,data_L=0;
	data_H = ( 0x0F00 & data) >> 8;
	data_L = 0X00FF & data ;
	IIC_Start();
	IIC_Send_Byte(0XC0);      //器件寻址,器件代吗:1100; 地址位A2,A1,A0为 0 , 0 , 0;-> 1100 0010
    IIC_Wait_Ack();	 
    IIC_Send_Byte(data_H); 	
    IIC_Wait_Ack();	 
    IIC_Send_Byte(data_L);
	IIC_Wait_Ack();	
    IIC_Stop();//产生一个停止条件  	
	Delay_ms(10);	
}
MCP4725.h代码:
#ifndef __MCP4725_H
#define __MCP4725_H
#include "myIIC.h"   


#define VREF_5V      3260//这个数值根据自己给模块的供电电压而定

void MCP4725_Init(void);
void MCP4725_WriteData_Digital(u16 data);
void MCP4725_WriteData_Voltage(u16 Vout);

#endif

main.c代码:
#include "stm32f10x.h"                  // Device header
#include "Delay.h"

#include "MCP4725.H"
#include "myIIC.H"
 
int main(void)
{

	MCP4725_Init();
	
	while(1)
	{ 
		MCP4725_WriteData_Voltage(1500);
		
	}
}

实测过,代码绝对可用,初学者,还请多多关照!

物联沃分享整理
物联沃-IOTWORD物联网 » STM32F103C8T6与MCP4725外部DAC的源码及接线指南

发表评论