这段时间项目中正好要做一个双通道电压放大电路,因为去年底才开始学习单片机的缘故对协议还不是很熟练,这里正好用到了PGA113这款可控增益放大芯片。使用stm32G030K6T6编写程序(主频率64MHz),因为对控制速度没有要求,所以不使用硬件SPI。
电路如上图所示,仪表放大器INA826放大100倍 隔直 再偏置1.65v后输入PGA113的CH1通道,同时给PGA113的VREF端提供1.65v(使用一个运放作为跟随器,反馈电阻10k偏大会产生震荡,实际减少至100Ω)以满足参考电位需求。
下面是软件SPI代码,基于模式0的写操作,另外这里用不到读操作,读操作是AI生成,我没有验证不确定有没有问题。
#ifndef INC_PGA113_H_
#define INC_PGA113_H_
#include "main.h"
/****************寄存器操作********************/
// 定义引脚
#define CS1_PIN GPIO_PIN_8
#define CS2_PIN GPIO_PIN_2
#define DIO_PIN GPIO_PIN_1
#define SCLK_PIN GPIO_PIN_0
//
定义端口
#define CS1_GPIO_PORT GPIOA
#define CS2_GPIO_PORT GPIOB
#define DIO_GPIO_PORT GPIOB
#define SCLK_GPIO_PORT GPIOB
//
GPIO操作宏
#define PGA_CS1_HIGH (CS1_GPIO_PORT->BSRR = CS1_PIN)
#define PGA_CS1_LOW (CS1_GPIO_PORT->BSRR = (uint32_t)CS1_PIN << 16U)
#define PGA_CS2_HIGH (CS2_GPIO_PORT->BSRR = CS2_PIN)
#define PGA_CS2_LOW (CS2_GPIO_PORT->BSRR = (uint32_t)CS2_PIN << 16U)
#define PGA_DIO_HIGH (DIO_GPIO_PORT->BSRR = DIO_PIN)
#define PGA_DIO_LOW (DIO_GPIO_PORT->BSRR = (uint32_t)DIO_PIN << 16U)
#define PGA_CLK_HIGH (SCLK_GPIO_PORT->BSRR = SCLK_PIN)
#define PGA_CLK_LOW (SCLK_GPIO_PORT->BSRR = (uint32_t)SCLK_PIN << 16U)
/****************HAL_IO操作********************/
//#define PGA_CS1_HIGH HAL_GPIO_WritePin(GPIOA, CS1_Pin, GPIO_PIN_SET)
//#define PGA_CS1_LOW HAL_GPIO_WritePin(GPIOA, CS1_Pin, GPIO_PIN_RESET)
//#define PGA_CS2_HIGH HAL_GPIO_WritePin(GPIOB, CS2_Pin, GPIO_PIN_SET)
//#define PGA_CS2_LOW HAL_GPIO_WritePin(GPIOB, CS2_Pin, GPIO_PIN_RESET)
//#define PGA_DIO_HIGH HAL_GPIO_WritePin(GPIOB, DIO_Pin, GPIO_PIN_SET)
//#define PGA_DIO_LOW HAL_GPIO_WritePin(GPIOB, DIO_Pin, GPIO_PIN_RESET)
//#define PGA_CLK_HIGH HAL_GPIO_WritePin(GPIOB, SCLK_Pin, GPIO_PIN_SET)
//#define PGA_CLK_LOW HAL_GPIO_WritePin(GPIOB, SCLK_Pin, GPIO_PIN_RESET)
void Delay_us(uint8_t cycles);
void SetGain(uint8_t ch,uint8_t gain);
#endif /* INC_PGA113_H_ */
这里由于我一个板子有2个PGA113,所以在 函数上做了一个选择,chip对应拉低某个cs引脚
#include "PGA113.h"
uint16_t gainBuffer[8]={ 0x2a01,0x2a11,0x2a21,0x2a31,0x2a41,0x2a51,0x2a61,0x2a71 };//定义增益数组
void SPI_Transmit16(uint8_t chip, uint16_t data) {/* 发送一个16位的数据 */
PGA_CS1_HIGH;
PGA_CS2_HIGH;
PGA_CLK_LOW;
if (chip == 1) {
PGA_CS1_LOW;
PGA_CS2_HIGH;
}else {
PGA_CS1_HIGH;
PGA_CS2_LOW;
}
for (uint16_t i = 0; i < 16; i++) {//发送16位数据
if (data & 0x8000) {//检查最高位
PGA_CLK_LOW;
PGA_DIO_HIGH;
}else{
PGA_CLK_LOW;
PGA_DIO_LOW;
}
data <<= 1; //数据左移一位
Delay_us(5);
PGA_CLK_HIGH;//上升沿捕获数据
Delay_us(5);
}
PGA_DIO_LOW; //通信结束,释放所有引脚
PGA_CLK_LOW;
Delay_us(10);
PGA_CS1_HIGH;
PGA_CS2_HIGH;
}
uint16_t SPI_Receive16(void) {/*接收一个16位的数据*/
uint16_t received_data = 0;
for (uint16_t i = 0; i < 16; i++) {
received_data <<= 1;//为下一位腾出空间
PGA_CLK_LOW;//确保数据线稳定时拉低时钟
Delay_us(64);//确保时钟低电平持续足够时间,准备接收数据
PGA_CLK_HIGH;//时钟上升沿,数据被设备输出至DIO
Delay_us(64);//确保时钟高电平持续足够时间,数据稳定
if (HAL_GPIO_ReadPin(GPIOB, DIO_Pin) == GPIO_PIN_SET) {//读取DIO引脚的状态
received_data |= 0x01; //如果DIO为高,将当前最低位设为1
}
}
return received_data;
}
void SetGain(uint8_t ch,uint8_t gain){
uint8_t gtemp=0;
switch(gain)
{
case 1:
gtemp=0;
break;
case 2:
gtemp=1;
break;
case 5:
gtemp=2;
break;
case 10:
gtemp=3;
break;
case 20:
gtemp=4;
break;
case 50:
gtemp=5;
break;
case 100:
gtemp=6;
break;
case 200:
gtemp=7;
break;
default:
return;
}
SPI_Transmit16(ch,gainBuffer[gtemp]);
}
void Delay_us(uint8_t cycles) {/*短延时*/
while (cycles--) {
__asm volatile("NOP");
}
}
SetGain(1,10);//芯片1放大10倍
这里记录一下调试过程中出现的马虎问题,因为要配置CH1通道,下意识写了一个0x2ax2,实际上应该是0x2ax1,因为描述通道选择的表格还在下面没有看到,这导致直接浪费了3天时间,外加2片芯片(以为坏了,重新买了2片)
如上图所示选择CH1应该是01,而非02,如果写02则无输出。
最后记录一下逻辑分析仪结果 D3为cs,D1为clk,D0为DIO