主题中讨论的其他器件:MSP430FR4133、 INA2128、 INA128
我的电路当前使用 MSP430FR4133通过 SPI 与 ADS8353通信。 我们开发了代码和架构、在给定输入信号的情况下输出有效数据。 当我们尝试过采样时(例如、通过 A、循环连续采样多达32次)、就会出现问题。 输出的值会显著下降、只需反复测量、两者之间没有延迟。 我们的低增益通道应读取450个计数、并使用单个采样执行此操作、但对于最终的32个过采样值、它会快速下降至大约320个计数。 当我在每次测量后放入延迟周期时、这似乎是固定的、但对于一个应该进行32次过采样并在10ms 内传送输出的仪器来说、过采样环路内等待8000个周期显然非常耗时。 此外、考虑到 ADS8353的数据表中具有采样能力、因此应该没有必要这样做。 代码会一直等待、直到发送一个命令字节(a-f、用于确定平均多少个过采样)、然后输出单次测量。 下面是仅在 UART 上输出最后一次过采样测量的代码、我将在该代码中分析输出。
另外需要注意的是,在退出待机模式(不是 SPD 模式,在启用输出内部基准电压的情况下,*应该*花费3ms 的 SPD 模式)后,ADC 在 MCU 中输出有效数据需要很长的周期延迟(0.5ms)。 这是通过实验确定的、直到增加等待时间后、输出数据才会发生任何变化。 下面包括运行 MSP430FR4133并与 ADS8353通信的代码。
MCU 代码:
//指定电路板 ID#常数
#define Board_ID 0b01000000
//指定过采样常量
//#define NOP 32
//#define RS 5
//包括库
#include
#include
#include
#include
//声明函数
void SYSTEMinit();
void writeUART (char*语句);
INT 模拟(int 通道);
void GPIOinit();
//声明全局变量
volatile uint8_t HKID = 0;
volatile uint8_t MSR_FG = 0;
volatile uint8_t MSR_CMD = 0;
int main (空)
{
//声明函数变量
INT j、NOP、RS;
uint16_t value[4];
长平均值1;
长平均值2;
uint8_t data[6];
uint8_t LightSensor;
uint16_t HK;
//执行系统初始化功能
SYSTEMMINIT();
//_bis_SR_register (LPM0_bits | GIE);
//启用中断
_bis_SR_register (GIE);
//无限操作循环
while (1)
{
//如果 ISR 已激活测量标志
如果(MSR_FG = 1)
{
//将求和变量初始化为0
平均值1 = 0;
平均值2 = 0;
HKID = HKID % 5; //循环5个选项;Temp1、2、+15、-15、-15、 5.
如果(模拟(7)> 256)
{
LightSensor = 0b00100000;
}
其他
{
LightSensor = 0b00000000;
}
HK =模拟(HKID+2);
DATA[0]= Board_ID + LightSensor +(HKID << 2)+(HK >> 8);
HKID++;
数据[1]=HK;
//命令查找
开关(MSR_CMD)
{
案例"e":
NOP = 32;
Rs = 5;
中断;
案例'f':
NOP = 64;
Rs = 6;
中断;
案例"A":
NOP = 1;
Rs = 0;
中断;
情况"b":
NOP = 4;
Rs = 2;
中断;
案例'c':
NOP = 8;
Rs = 3;
中断;
案例"d":
NOP = 16;
Rs = 4;
中断;
默认值:break;
}
UCB0CTLW0 |= UCSWRST; //允许编辑几乎所有以下位。
UCB0CTLW0 &=~ UCCKPH; //数据在第一个边沿发生更改并在第二个边沿被捕捉
UCB0CTLW0 &=~ UCSWRST;
//配置 ADC
//配置 CFR (配置寄存器)
P5OUT &=~ BIT0; //激活通道选择
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x86;
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x40;
//发送四个字节的零来完成帧
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
P5OUT |= BIT0; //取消激活通道选择
_delay_cycles (24);
//配置 REFDAC A (内部基准)
P5OUT &=~ BIT0; //激活通道选择
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x91;
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0xFF;
//发送四个字节的零来完成帧
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00;
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
P5OUT |= BIT0; //取消激活通道选择
//配置 REFDAC B (内部基准)
P5OUT &=~ BIT0; //激活通道选择
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0xA1;
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0xFF;
//发送四个字节的零来完成帧
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
P5OUT |= BIT0; //取消激活通道选择
UCB0CTLW0 |= UCSWRST; //允许编辑几乎所有以下位。
UCB0CTLW0 |= UCCKPH; //数据在第一个边沿发生变化,在第二个边沿被捕捉
UCB0CTLW0 &=~ UCSWRST;
// while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
//while (UCB0STATW 和 UCBUSY);
_delay_cycles (8000); // ADC 预热时间
对于(j = 0、<NoP; j++)
{
P5OUT &=~ BIT0; //激活通道选择线
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
(void) UCB0RXBUF; //以防万一、清除 Rx 缓冲器
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (UCB0STATW 和 UCBUSY); // SPI B0缓冲器就绪?
值[0]= UCB0RXBUF; //存储 ADC 数据的8位
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (UCB0STATW 和 UCBUSY); // SPI B0缓冲器就绪?
值[1]= UCB0RXBUF; //存储8位 ADC 数据
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (UCB0STATW 和 UCBUSY); // SPI B0缓冲器就绪?
值[2]= UCB0RXBUF; //存储8位 ADC 数据
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (UCB0STATW 和 UCBUSY); // SPI B0缓冲器就绪?
值[3]= UCB0RXBUF; //存储8位 ADC 数据
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
P5OUT |= BIT0; //取消激活通道选择线路
//_DELAY_CYCLES (8000);
//每个通道的总和平均值
average1 +=(value[0]<<8)+ value[1];
average2 +=(value[2]<<8)+ value[3];
//if (j=1)
{
DATA[2]= Value[0];//仅输出用于故障排除的最终数据值
数据[3]=值[1];
数据[4]=值[2];
数据[5]=值[3];
}
}
//右移平均值转换为平均值
average1 = average1 >> rs;
average2 = average2 >> rs;
/*//通过 LSB 的直接分配和向右移位来分配数据字节,从而仅获取 MSB
DATA[2]= average1 >> 8;
DATA[3]=平均值1;
DATA[4]=平均2 >> 8;
DATA[5]=平均值2;*/
//通过 UART 传输数据
while (!(UCA0IFG&UCTXIFG)); //轮询发送标志
UCA0TXBUF = DATA[0]; //发送数据字节
while (!(UCA0IFG&UCTXIFG)); //轮询发送标志
UCA0TXBUF = DATA[1]; //发送数据字节
while (!(UCA0IFG&UCTXIFG)); //轮询发送标志
UCA0TXBUF = DATA[2]; //发送数据字节
while (!(UCA0IFG&UCTXIFG)); //轮询发送标志
UCA0TXBUF = DATA[3]; //发送数据字节
while (!(UCA0IFG&UCTXIFG)); //轮询发送标志
UCA0TXBUF = DATA[4]; //发送数据字节
while (!(UCA0IFG&UCTXIFG)); //轮询发送标志
UCA0TXBUF = DATA[5]; //发送数据字节
//
P5OUT &=~ BIT0; //激活通道选择
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x86; //
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x60; //
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
P5OUT |= BIT0; //取消激活通道选择
//重置测量标志
MSR_FG=0;
//进入低功耗模式
//_bis_SR_register (LPM0_bits);
}
}
}
//计时器 A0中断服务例程
#if defined (__TI_Compiler_version__)|| Defined (__IAR_systems_ICC__)
#pragma vector = TIMER0_A0_vector
_interrupt void Timer_A (void)
#Elif defined (_GNU_)
void __attribute__((interrupt (TIMER0_A0_vector)) Timer_A (void)
其他
错误编译器不受支持!
#endif
{
WDTCTL = WDTPW + WDTCNTCL; //提供密码并清除看门狗计时器
TA0CCR0 += 30000; //操纵此值以影响周期。 会直接呈线性变化。 确保其与上面的值相匹配。 30000=3.9ms 周期。
}
// UART 中断服务例程
#if defined (__TI_Compiler_version__)|| Defined (__IAR_systems_ICC__)
#pragma vector=USCI_A0_Vector
_interrupt void USCI_A0_ISR (void)
#Elif defined (_GNU_)
void __attribute__((中断(USCI_A0_Vector)) USCI_A0_ISR (void)
其他
错误编译器不受支持!
#endif
{
switch (__evo_in_range (UCA0IV、USCI_UART_UCTXCPTIFG))
{
USCI_NONE 案例:中断;
USCI_UART_UCRXIFG 案例:
UCA0IFG &=~ UCRXIFG; //清除中断
MSR_CMD = UCA0RXBUF; //记录命令字
MSR_FG = 1; //激活测量命令标志
中断;
案例 USCI_UART_UCTXIFG:中断;
案例 USCI_UART_UCSTTIFG:中断;
案例 USCI_UART_UCTXCPTIFG:中断;
默认值:break;
}
}
空 SYSTEMMINIT()
{
WDTCTL = WDTPW | WDTHOLD; //停止看门狗计时器
GPIOinit();
//针对未连接条件的复位引脚
//SFRRPCR |= SYSRSTUP + SYSRSTRE; //为复位引脚启用上拉电阻。 计划使用一个外部电阻器、因此这是不必要的、因为硬件解决了这个问题。
//配置 GPIO
P5DIR = 0x00; //将所有 DIR 设置为 USCIB 所需的输入
P5DIR |= BIT0; //用作通道选择(SPI)的 I/O 引脚
P5OUT |= BIT0; //将通道选择引脚设置为低电平
P5SEL0 = 0x0E; //与上述相同。 将端口5引脚1-3的全部设置为1
P1SEL0 |= BIT0 + BIT1; //将2-UART 引脚设置为主要非 I/O 功能
//时钟配置
FRCTL0 = FRCTLPW | NWAITS_1; //配置等待状态 thingy。 速度高于8MHz 时所需的
_bis_SR_register (SCG0); //禁用 FLL
PM5CTL0 &=~LOCKLPM5; //将引脚锁定到位
CSCTL3 |= SELREF_REFOCLK; //将 REFO 设置为 FLL 基准源
CSCTL0 = 0; //清除 DCO 和 MOD 寄存器
CSCTL1 &=~(DCORSEL_7); //首先清除 DCO 频率选择位
CSCTL1 |= DCORSEL_5; //设置 DCO = 16MHz
CSCTL2 = FLLD_0 + 487; // DCODIV = 16MHz
_DELAY_CYCLES (3);
_BIC_SR_register (SCG0); //启用 FLL
while (CSCTL7 &(FLLUNLOCK0 | FLLUNLOCK1)); // FLL 锁定
CSCTL4 = SELMS_DCOCLKDIV; //默认 DCODIV SMCLK 源
//计时器配置
TA0CCTL0 |= CCIE; //启用 TACCR0中断
TA0CCR0 = 30000; //操纵此值来调整时间频率。 以线性方式直接随周期变化。
TA0CTL |= tassel_SMCLK | MC__Continous; // SMCLK,连续模式
WDTCTL = WDTPW + WDTIS_4; //将看门狗设置为看门狗模式以每4ms 触发一次,使用 SMCLK
UCA0CTLW0 |= UCSWRST; //允许配置 UART
UCA0CTLW0 |= UCSSEL_SMCLK; //选择 SMCLK 作为 UART 的时钟源
UCA0BR0 = 8; // 16MHz 至115.2k 波特率。 请参阅表(第589页)
UCA0MCTLW = 0xF700 | UCOS16 | UCBRF_10;
UCA0CTLW0 &=~UCSWRST; //初始化 eUSCI
_enable_interrupt ();
UCA0IE |= UCRXIE; //启用 USCI_A0 RX 中断
ADCCTL0 |= ADCSHT_2 + ADCON; // ADCON、S&H=32 ADC CLKS
ADCCTL1 &=~ ADCCONSEQ0 + ADCCONSEQ1; //设置单次转换单通道模式
ADCMCTL0 |= ADCSREF_1; //将刻度顶部设置为1.5V、底部设置为接地
ADCCTL1 |= ADCSHP;
ADCCTL1 |= ADCSSEL_0; // ADCCLK =约5MHz 的 MODOSC
ADCCTL2 |= ADCRES_1; // 0提供8位,1提供10位,2提供12位。
PMMCTL0_H = PMMPW_H; //解锁 PMM 寄存器。 温度传感器所需
PMMCTL2 |= INTREFEN; //启用内部基准
_DELAY_CYCLES (400); //基准趋稳延迟
UCB0CTLW0 |= UCSWRST; //允许编辑几乎所有以下位。
UCB0CTLW0 &=~ UCCKPH; //数据在第一个边沿发生更改并在第二个边沿被捕捉
UCB0CTLW0 &=~ UCCKPL; //非活动状态为高电平
UCB0CTLW0 |= UCMSB; //最高有效位优先
UCB0CTLW0 &=~ UC7BIT; // 8位数据
UCB0CTLW0 |= UCMST; //将 MSP 设置为主控模式
UCB0CTLW0 |= UCMODE1; //低电平有效的4引脚模式、在 STE (M?)时使能从器件 = 0
UCB0CTLW0 |= UCSYNC; //同步模式,共享时钟
UCB0CTLW0 |= UCSSEL_SMCLK; //选择特定于器件的模式、即 SMCLK (16MHz)
UCB0BRW = 0x01; //将 SPI 的共享时钟除以2
UCB0CTLW0 |= UCSTEM; //为4线制从机生成使能信号
UCB0CTLW0 &=~ UCSWRST; //启用机器
//配置 ADC
//配置 CFR (配置寄存器)
P5OUT &=~ BIT0; //激活通道选择
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x86;
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x60;
//发送四个字节的零来完成帧
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
P5OUT |= BIT0; //取消激活通道选择
//配置 REFDAC A (内部基准)
P5OUT &=~ BIT0; //激活通道选择
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x91;
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0xFF;
//发送四个字节的零来完成帧
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
P5OUT |= BIT0; //取消激活通道选择
//配置 REFDAC B (内部基准)
P5OUT &=~ BIT0; //激活通道选择
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0xA1;
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0xFF;
//发送四个字节的零来完成帧
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
UCB0TXBUF = 0x00; //发送8个零
while (((UCB0IFG & UCTXIFG)=0); //轮询发送标志
P5OUT |= BIT0; //取消激活通道选择
//_DELAY_CYCLES (16000);
UCB0CTLW0 |= UCSWRST; //允许编辑几乎所有以下位。
UCB0CTLW0 |= UCCKPH; //数据在第一个边沿发生变化,在第二个边沿被捕捉
UCB0CTLW0 &=~ UCSWRST;
}
INT 模拟(int 通道)
{
ADCCTL0 &=~ ADCENC; //取消启用 ADC 以便可以更改输入通道
如果(通道= 2) //在不改变基准电压的情况下改变输入通道
{
ADCMCTL0 = ADCINCH_2 + ADCSREF_1; // A2 =+5V
}
如果(通道== 3)
{
ADCMCTL0 = ADCINCH_3 + ADCSREF_1; // A3 =-15
}
如果(通道== 4)
{
ADCMCTL0 = ADCINCH_4 + ADCSREF_1; // A4 =+15
}
如果(通道== 5)
{
ADCMCTL0 = ADCINCH_5 + ADCSREF_1; // A5 =温度1
}
如果(通道== 6)
{
ADCMCTL0 = ADCINCH_6 + ADCSREF_1; // A6 =温度2
}
如果(通道== 7)
{
ADCMCTL0 = ADCINCH_7 + ADCSREF_1; // A7 =光传感器
}
ADCIFG &=~ADCIFG0; //清除标志
ADCCTL0 |= ADCENC | ADCSC; //开始 ADC 转换
while ((ADCIFG & ADCIFG0)=0); //轮询标志被触发
返回 ADCMEM0;
}
空 writeUART (char*语句)
{
int i;
对于(i = 0;i < strlen (句子);i++){
while (!(UCA0IFG&UCTXIFG));
UCA0TXBUF =句子[i];
}
返回;
}
空 GPIOinit()
{
//这会引起一个初始0x00在串行端口上输出
P1DIR = 0xFF;P2DIR = 0xFF;P3DIR = 0xFF;P4DIR = 0xFF;
P5DIR = 0xFF;P6DIR = 0xFF;P7DIR = 0xFF;P8DIR = 0xFF;
P1REN = 0xFF;P2REN = 0xFF;P3REN = 0xFF;P4REN = 0xFF;
P5REN = 0xFF;P6REN = 0xFF;P7REN = 0xFF;P8REN = 0xFF;
P1OUT = 0x00;P2OUT = 0x00;P3OUT = 0x00;P4OUT = 0x00;
P5OUT = 0x00;P6OUT = 0x00;P7OUT = 0x00;P8OUT = 0x00;
返回;
}