GD32F103模拟SPI(AD5689为例)

AD5689是双通道、16位的DAC,用于输出模拟电压信号。SPI协议传输。

一、了解芯片各个引脚的功能

写驱动前,需要读懂时序图,从时序图中提取SPI传输的有用信息

1、SCLK为时钟线

空闲的时为高电平(即DIN没有数据的时候),由此可见,SPI协议的时钟极性为高电平(CPOL=1)。

2、SYNC(片选)

在SYNC(片选)拉低之后,在SCLK时钟的下降沿进行数据采样(如图所示,DIN在SCLK下降沿的时候保持稳定),因此是在第一个时钟沿进行采样(CPHA=0)。

3、SDIN引脚

SDIN,数据传输引脚传输的第一位数据是DB23,为MSB(高位优先;另一种则是低位优先LSB)。24位数据具体的含义如下图:

4、SDO引脚

SDO,用于数据输出。SPI通信拥有数据输入和输出两个信号线,可以推测其为全双工模式;通信双方共用时钟线,为同步通信

5、其它引脚

关于其它的引脚,如Vcc,RESET,Vout,为电源、复位、输出等功能,不是SPI特有,本文就不一一介绍。

二、初始化芯片引脚

上电后对需对芯片进行重启,保证其工作状态稳定。硬件连接根据自身情况设计。直接上代码。

/**
  * @brief DAC1初始化
  * @Param None
  * @retval None
  */
void Dac1_init(void)
{
	rcu_periph_clock_enable(RCU_GPIOA);//使能GPIOA时钟
	rcu_periph_clock_enable(RCU_GPIOB);
	rcu_periph_clock_enable(RCU_GPIOC);
	
	//PA4-片选 PA5-CLK PA6-MISO PA7-MOSI
	gpio_init(GPIOA,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_7); //推挽输出
	gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,GPIO_PIN_6); //浮空输入
	
	//更新数据引脚
	gpio_init(GPIOC,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_4); //推挽输出 PC4 LDAC
	gpio_init(GPIOB,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_0); //推挽输出 PB0 reset

	GPIO_BOP(CSS_PORT) = CSS_PIN; //拉高片选,空闲状态
	//复位AD5689 拉高PC4和PB0
//	GPIO_BOP(RESET_PORT) = RESET_PIN; 
//	GPIO_BOP(LDAC_PORT) = LDAC_PIN; //引脚输出高电平
	
//	delay_1ms(1);
	
	GPIO_BC(RESET_PORT) = RESET_PIN; //拉低reset,芯片复位
	
	delay_1ms(1);
	
	GPIO_BOP(RESET_PORT) = RESET_PIN; //拉高reset
	
}
 三、读写操作

芯片手册上对于写操作的描述如下图

代码根据其写操作设计

1、写一位
 /**
  * @brief SPI发送bit为数据数据
  * @Param data:选择发送的数据
  * @retval None
  */
uint8_t Spi_send_bit(uint8_t data)
{
	uint8_t d=0;
	
	//MSB,最高有效位发送数据
	if(data == 1)
		GPIO_BOP(MOSI_PORT) = MOSI_PIN; //输出高电平
	else
		GPIO_BC(MOSI_PORT) = MOSI_PIN; //输出低电平
	
	//设置SCLK引脚为低电平,这个时候,从机会开始读取MOSI引脚电平
	GPIO_BC(SCK_PORT) = SCK_PIN; //输出低电平
	delay_1us(2);
	
	//设置SCLK引脚为高电平,告诉从机,主机准备采集MISO电平
	GPIO_BOP(SCK_PORT) = SCK_PIN; //输出高电平
	delay_1us(2);

	   //主机采集MISO引脚电平
	if(GPIO_ISTAT(MISO_PORT)&(MISO_PIN))
		d = 1; 
	
	return d;
}
2、写一个字节
 /**
  * @brief SPI发送字节数据
  * @Param data:选择发送的数据
  * @retval None
  */
uint8_t Spi_send_byte(uint8_t data)
{
	int32_t i=0;
	uint16_t d=0;
	
	for(i=7; i>=0; i--)
	{
		//MSB,最高有效位发送数据
		if(data & (1<<i))
			GPIO_BOP(MOSI_PORT) = MOSI_PIN; //输出高电平
		else
			GPIO_BC(MOSI_PORT) = MOSI_PIN; //输出低电平
		
		//设置SCLK引脚为低电平,这个时候,从机会开始读取MOSI引脚电平
		GPIO_BC(SCK_PORT) = SCK_PIN; //输出低电平
		delay_1us(2);
		
		//设置SCLK引脚为高电平,告诉从机,主机准备采集MISO电平
		GPIO_BOP(SCK_PORT) = SCK_PIN; //输出高电平
		delay_1us(2);
  	
           //主机采集MISO引脚电平
		if(GPIO_ISTAT(MISO_PORT)&(MISO_PIN))
			d|=1<<i; 
	}
	return d;
}
3、写半字(16bit)
 /**
  * @brief SPI发送半字数据
  * @Param data:选择发送的数据
  * @retval None
  */
uint16_t Spi_send_halfword(uint16_t data)
{
	int32_t i=0;
	uint16_t d=0;
	
	for(i=15; i>=0; i--)
	{
		//MSB,最高有效位发送数据
		if(data & (1<<i))
			GPIO_BOP(MOSI_PORT) = MOSI_PIN; //输出高电平
		else
			GPIO_BC(MOSI_PORT) = MOSI_PIN; //输出低电平
		
		//设置SCLK引脚为低电平,这个时候,从机会开始读取MOSI引脚电平
		GPIO_BC(SCK_PORT) = SCK_PIN; //输出低电平
		delay_1us(2);
		
		//设置SCLK引脚为高电平,告诉从机,主机准备采集MISO电平
		GPIO_BOP(SCK_PORT) = SCK_PIN; //输出低电平
		delay_1us(2);
  	
           //主机采集MISO引脚电平
		if(GPIO_ISTAT(MISO_PORT)&(MISO_PIN))
			d|=1<<i; 
	}
	return d;
}
4、读操作

之前已述SPI为全双工通信(发送的同时会给你回数据)。但他本次回给你的数据,是在会有你上次发的命令。所以,在发数据之后,再次发送一次数据时,回的才是你想要的数据。如下图所示

回读操作包含在了写操作,可去看写操作中的回去逻辑。

四、应用

读写操作完成之后,即可根据不同厂家SPI芯片提供的通信协议,编写不同的功能逻辑代码,来实现自身的需求。

以下有我自己的例程,仅供大家参考

设置命令0x39-->0011(写入并更新DAC通道) 1001(同时设置A、B两个通道)

回读命令0x91-->1001(回读使能) 0001(回读DAC通道A的值)

 /**
  * @brief 设置AD7689的ad值0~65535
  * @Param data:选择发送的数据
  * @retval None
  */
uint16_t AD5689_setval(float val)
{
	if(val <= 3.3)
	{
		/*gain = 0,输出电压 0~Vref(2.5V)
		0~65535 <--> 0~2.5v*/
		uint16_t num = val/2.5*65535/1.028;
		
		GPIO_BC(CSS_PORT) = CSS_PIN; //拉低片选
		delay_1us(1);
		Spi_send_byte(0x39);
		Spi_send_halfword(num);
		delay_1us(1);
		GPIO_BOP(CSS_PORT) = CSS_PIN; //拉高片选
//		printf("set val %f ok\r\n",val);

	}
	return 0;
}


/**
  * @brief 回读DAC寄存器的值
  * @Param None
  * @retval None
  */
uint16_t AD5689_readval(void)
{
	uint16_t num = 0;
	
	GPIO_BC(CSS_PORT) = CSS_PIN; //拉低片选
	delay_1us(1);
	Spi_send_byte(0x91);
	Spi_send_halfword(0x0000);
	
	GPIO_BOP(CSS_PORT) = CSS_PIN; //拉高片选
	delay_1us(1);
	
	GPIO_BC(CSS_PORT) = CSS_PIN; //拉低片选
	delay_1us(1);
	
	for(int i = 0; i < 4 ;i++)
	{
		Spi_send_bit(0);
	}
	num = Spi_send_halfword(0x0000);
	
	for(int i = 0; i < 4 ;i++)
	{
		Spi_send_bit(0);
	}
	GPIO_BOP(CSS_PORT) = CSS_PIN; //拉高片选
	//printf("0");
	return num;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值