This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
嗨!
我想在2个不同的模拟引脚(例如 PE2和 PE3)中输入2个不同的样本、然后进行经皮采样以在 UART 上打印、但我不知道如何配置 ADC。 有什么帮助? 注释代码和函数说明(例如、什么是序列发生器、如何将通道连接到 GPIO 引脚 以及如何使用 ADCSequenceStepConfigure 函数)将是极好的! (我曾尝试阅读一些论坛和 Tiva Ware 外设驱动程序的库文档、但我无法实现任何目标。 谢谢!
您好!
中有 TivaWare ADC 示例 /examples/peripherals/adc/single_ended.c。 尽管这仅采用一个模拟输入、但您可以将其扩展为采用多个通道。 我建议您先运行此示例、以了解 ADC 和 TivaWare 的工作原理、然后再扩展到多个通道。 以下代码适用于两个通道。
SysCtlPeripheralEnable (SYSCTL_Periph_ADC0); SysCtlPeripheralEnable (SYSCTL_Periph_GPIOE); GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_3 | GPIO_PIN_3); ADCSequenceConfigure (ADC0_BASE、0、ADC_TRIGGER_PROCESSOR、0); ADCSequenceStepConfigure (ADC0_BASE、0、0、ADC_CTL_CH0); ADCSequenceStepConfigure (ADC0_BASE、0、1、ADC_CTL_CH1 | ADC_CTL_IE | ADC_CTL_END); ADCSequenceEnable (ADC0_BASE、0); ADCIntClear (ADC0_BASE、0);
查尔斯
我已切换到 PE2和 PE1。 这似乎解决了我的问题、因为两个通道相互影响。 然而、尽管输入非常稳定、它们仍会波动近100个计数(我通过简单设置了几节1.5伏电池和一个分压器来查看通道如何响应)。 我应该期待不同的结果吗? 是否有必要进行硬件或软件过采样以获得更稳定的计数?
您好!
您是如何构建分压器的? 如果没有分压器、您能否馈入小于3.3V 的输入、您是否看到波动? 您 kΩ 在 ADC 输入与接地之间使用一个低值电阻器、理想情况下小于1k Ω。 请参阅 ADC 部分中的 TM4C123系统设计指南。 低电阻有助于将您的输入电压与内部采样电容器进行电荷耦合。
www.ti.com/.../spma059.pdf
这对我来说毫无意义。 您是否有其他板可供尝试?
嘿、Charles
嗯、首先、谢谢、但我的系统中有一个问题。 我想将 CH0属性为 PE1、将 CH1属性为 PE2。 但是,当我将信号源连接到 PE3时,它也会读取。 我该怎么做才能停止读取它? 以下是我的代码:
SysCtlPeripheralEnable (SYSCTL_Periph_ADC0);//启用 ADC0模块。 SysCtlPeripheralEnable (SYSCTL_Periph_GPIOE);//在 GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_2| GPIO_PIN_1)中为模拟启用 GPIOE; ADCSequenceConfigure (ADC0_BASE、3、ADC_TRIGGER_processor、0); ADCSequStepConfigure (ADC0_BASE、 3、0、ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END); ADCSequenceEnable (ADC0_BASE、3); ADCIntClear (ADC0_BASE、3);
嘿、Charles
我已经做了很多修改、但我的所有通道都相互干扰、即使 PE3也在这样做、尽管我不使用它。
以下是我的代码:
void init_adc (void) { SysCtlPeripheralEnable (SYSCTL_Periph_ADC0);//启用 ADC0模块。 SysCtlPeripheralEnable (SYSCTL_Periph_GPIOE);//在 GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_1)中为模拟启用 GPIOE; GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_2); ADCReferenceSet (ADC0_BASE、 ADC_REF_INT); ADCIntEnable (ADC0_BASE、3); ADCSequenceConfigure (ADC0_BASE、0、 ADC_TRIGGER_PROCESSOR, 0); //ADCSequenceConfigure (ui32Base、ui32SequenceNum、ui32Trigger、ui32Priority) //参数: // ui32Base 是 ADC 模块的基址。 // ui32SequenceNum 是采样序列编号。 // ui32Trigger 是启动采样序列的触发源;必须是 // adc_trigger___LW_AT__∗值之一。 // ui32Priority y 是采样序列相对于其它采样 序列的相对优先级//序列。 ADCSequenceStepConfigure (ADC0_BASE、0、0、ADC_CTL_CH1);//将 AIN1映射到 SS0 ADCSequenceStepConfigure 的第0步 (ADC0_BASE、0、1、ADC_CTL_CH2 | ADC_CTL_IE | ADC_CTL_END);//将 AIN2映射到 SS0的第1步并生成该通道 //序列发生器中的最后一步,也生成 //序列发生器完成时中断 ADCSequenceEnable (ADC0_BASE、0); ADCIntClear (ADC0_BASE、0); }
还可以! 我已经更改了所有内容,但通道之间仍然存在干扰,例如,当我将任何信号源连接到 PE2或 PE1时,UART 也会读取和打印一些信号。 即使我将这些引脚接地、它仍然显示一个奇怪的方波。 我该怎么做?
以下是我的 Get 示例代码:
while (!ADCIntStatus (ADC0_BASE、0、false) { } ADCIntClear (ADC0_BASE、0); ADCSequenceDataGet (ADC0_BASE、0、通道1); while (!ADCIntStatus (ADC0_BASE、0、false) { } ADCIntClear (ADC0_BASE、0); ADCSequenceDataGet (ADC0_BASE、0、通道2); normalizedADC =((浮点)通道2)/4096.0f; UARTprintf ("%d\r"、normalizedADC); UARTprintf ("\n");
我看不到您调用 ADCProcessorTrigger (ADC0_BASE、0)。 如何触发转换以开始?
我之前问过您是否按原样尝试过 TivaWare 示例。 如果将输入连接到0V、3.3V 或1.65V、您是否获得了正确的转换数据? 你得到了什么?
嗯、 我使用计时器从另一个函数触发它。 我在一个通道中放置了一个5Hz、它与另一个通道的一些噪声混合。 另一件事是、所有模拟引脚都对信号输入做出响应、并将一些值打印到串行端口。
是的!
这是:
#include #include #include #include "inc/hw_ints.h" #include "inc/hw_memmap.h" #include "driverlib/adc.h" #include "driverlib/debug.h" #include "driverlib/gpio.h" #include "driverlib/interrupt.h" #include "driverlib/rom.h"#include "driverlink/intraduateg.ide"#def/udio.idt/idr.idr.idr.idr.idr.idr.idr.idr.idr.idr.idr.idr.idr./idr.idr.idr.idr./idr.idr.idr.idr.idr.idr.idr./idr.idr.idr.idr.idr.idr.idr.idr.idr.idr.idr. //启用用于 UART1引脚的 GPIO 端口 A。 // TODO:将其更改为您正在使用的 GPIO 端口。 // SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA); // //为端口 A0和 A1上的 UART1功能配置引脚复用。 //如果您的器件不支持引脚复用、则无需执行此步骤。 // TODO:更改此选项以选择您正在使用的端口/引脚。 // GPIOPinConfigure (GPIO_PA0_U0RX); GPIOPinConfigure (GPIO_PA1_U0TX); // //启用 UART1,以便我们可以配置时钟。 // SysCtlPeripheralEnable (SYSCTL_Periph_UART0); //为这些引脚选择替代(UART)功能。 // TODO:更改此选项以选择您正在使用的端口/引脚。 // GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1); // //初始化控制台 I/O 的 UART UARTStdioConfig (0、115200、SysCtlClockGet ()/*16000000*/); } 空 Timer0BIntHandler (空) { //function description ->每次中断发生 // 中断标志被清除,以便另一个中断标志被清除 // 直到在无限循环中达到溢出。 // 然后、ADC 转换被触发以开始进行 // 要在 UART 上显示的样本。 //清除计时器中断标志。 // TimerIntClear (TIMER0_BASE、TIMER_TIMB_TIMEOUT); //触发 ADC 转换。 // //ADCProcessorTrigger (ADC0_BASE、3); ADCProcessorTrigger (ADC0_BASE、0); } void init_ADC (void) { SysCtlPeripheralEnable (SYSCTL_Periph_ADC0);//启用 ADC0模块。 SysCtlPeripheralEnable (SYSCTL_Periph_GPIOD);//在 GPIOPinTypeADC (GPIO_PORTD_BASE、GPIO_PIN_1)中为模拟启用 GPIOE;//通道6 GPIOPinTypeADC (GPIO_PORTD_BASE、GPIO_PIN_2);//通道5 //CINT_ADC0 (ADCINT )基址;ADC0_ADCINT (ADC0)基址 0); ADCSequenceConfigure (ADC0_BASE、0、ADC_TRIGGER_PROCESSOR、0); //ADCSequenceConfigure (ui32Base、ui32SequenceNum、ui32Trigger、ui32Priority) //参数: // ui32Base 是 ADC 模块的基址。 // ui32SequenceNum 是采样序列编号。 // ui32Trigger 是启动采样序列的触发源;必须是 // adc_trigger___LW_AT__∗值之一。 // ui32Priority y 是采样序列相对于其它采样 序列的相对优先级//序列。 ADCSequenceStepConfigure (ADC0_BASE、0、0、ADC_CTL_CH5);//将 AIN5映射到 SS0 ADCSequenceStepConfigure 的第0步 (ADC0_BASE、0、1、ADC_CTL_CH6 | ADC_CTL_IE | ADC_CTL_END);//将 AIN6映射到 SS0的第1步并生成该通道 //序列发生器中的最后一步,也生成 //序列发生器完成时中断 ADCSequenceEnable (ADC0_BASE、0); ADCIntClear (ADC0_BASE、0); } int main (void) { //该数组用于存储从 ADC FIFO 读取的数据。 它 //必须与正在使用的序列发生器的 FIFO 一样大。 此示例 //使用 FIFO 深度为1的序列3。 如果是另一个序列 //与更深的 FIFO 一起使用,则必须更改数组大小。 uint32_t channel1;//通道0数组 uint32_t channel2;//通道1数组 //变量->uint32_t ui32PrevCount = 0; //--- //初始配置-> SysCtlClockSet (SYSCTL_SYSDIV_1 | SYSCTL_USE_PLL | SYSCTL_OSC_main | SYSCTL_XTAL_16MHz);//将时钟设置为直接从外部晶振/振荡器运行。 ROM_SysCtlPeripheralEnable (SYSCTL_Periph_GPIOC);//为 LED 启用 GPIOC ROM_SysCtlPeripheralEnable (SYSCTL_Periph_TIMER0);//启用 Timer0 ROM_SysCtlDelay (1); //--------------- //GPIO 配置-> ROM_GPIOPinTypeGPIOOutput (GPIO_PORTC_BASE、GPIO_PIN_5);//将 PC5配置为输出 ROM_GPIOPinTypeGPIOOutput (GPIO_PORTC_BASE、GPIO_PIN_4);//将 PC4配置为输出 ROM_GPIOPinTypeGPIOOutput (GPIO_PORTC_BASE、GPIO_PIN_6);//将 PC4配置为输出 ROM_GPIOTypeGPIOOutput (GPIO_PORTC_BASE、GPIO_PIN_6)--- //Timer Settings --> InitConsole();//UART 配置 //5-配置计时器 //将 Timer0B 配置为16位周期性计时器-->一直计数到65536 // //向量表 中的注册 timer0B 处理程序 IntRegister (INT_TIMER0B、Timer0BIntHandler); //在控制台上显示设置。 // TimerConfigure (TIMER0_BASE、TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PERIODICASE); // ! 重要 说明//将 Timer0B 加载值设置为1ms。 TimerLoadSet (TIMER0_BASE、TIMER_B、SysCtlClockGet ()/ 1000);//将 clok 除以1000次 // 即:160000 Hz; //启用处理器中断。 // IntMasterEnable(); // //将 Timer0B 中断配置为计时器超时。 // TimerIntEnable (TIMER0_BASE、TIMER_TIMB_TIMEOUT); // //在处理器(NVIC)上启用 Timer0B 中断。 // IntEnable (INT_TIMER0B); // //初始化中断计数器。 // G_ui32Counter = 0; // //启用 Timer0B。 // TimerEnable (TIMER0_BASE,TIMER_B); //--------------- //ADC 设置--> init_adc (); //--------------- //Variables -> float normalizedADC; while (1) {// 等待转换完成。 //ADC0 while (!ADCIntStatus (ADC0_BASE、0、false)//如果样本准备就绪,则让 UART 显示值 { } ADCIntClear (ADC0_BASE、0); ADCSequenceDataGet (ADC0_BASE、0、通道1); while (!ADCIntStatus (ADC0_BASE、0、false)//如果样本准备就绪,则 UART 显示值 { } ADCIntClear (ADC0_BASE、0); ADCSequenceDataGet (ADC0_BASE、0、通道2); normalizedADC =((float)通道2)/4096.0f; UARTprintf ("%d\r"、 normalizedADC); UARTprintf ("\n"); } }
您需要使用 SysCtlClockSet (SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_MAIN|SYSCTAL_XTAL_16MHz)将时钟设置为80MHz。 PLL VCO 输出为200MHz、您需要进行2.5分频才能达到80MHz。 您正在将器件配置为以200MHz 的频率运行、并除以1。
您好、Bruno、
您是否会介意分享您工作的代码? 我的问题仍然存在、我想进行比较。
谢谢!
Ken
大家好、
当然! (请随时向我询问任何内容)。以下内容:
// // Bruno Ribeiro Chaves //巴西- Minas Gerais / Belo Horizonte //@brunorchoraves1// project.c -配置 ADC0和 UART 以显示样片 // //********* #include #include #include #include "inc/hw_ints.h" #include "inc/hw_memmap.h" #include "driverlib/adc.h" #include "driverlib/debug.h" #include "driverlib/gpio.h" #include "driverlib/interrupt.h" #include "driverlib/rom.h" #include "driverlib/driverlib/trune.h"#include "driverlib/trunicl"#include "driverlib/drivers.idio"#include "driverlib/try"#include "driverlib.mdio.idio.h // //如果驱动程序库遇到错误,则调用的错误例程。 //// ***************** #ifdef debug void __error__(char *pcFilename、uint32_t ui32Line) { #endif static volatile uint32_t g_ui32Counter = 0;//计时器计数器变量 void InitConsole (void) { // //启用用于 UART1引脚的 GPIO 端口 A。 // TODO:将其更改为您正在使用的 GPIO 端口。 // SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA); // //为端口 A0和 A1上的 UART1功能配置引脚复用。 //如果您的器件不支持引脚复用、则无需执行此步骤。 // TODO:更改此选项以选择您正在使用的端口/引脚。 // GPIOPinConfigure (GPIO_PA0_U0RX); GPIOPinConfigure (GPIO_PA1_U0TX); //启用 UART1,以便我们可以配置时钟。 // SysCtlPeripheralEnable (SYSCTL_Periph_UART0); //使用内部16MHz 振荡器作为 UART 时钟源。 GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1); // //初始化控制台 I/O 的 UART // ///UARTConfigSetExpClk (UART0_BASE、SysCtlClockGet ()、115200、 // (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | // UART_CONFIG_PAR_NONE)); UARTStdioConfig (0、115200、SysCtlClockGet ()/*16000000*/); } 空 Timer0BIntHandler (空) { // //清除计时器中断标志。 // TimerIntClear (TIMER0_BASE、TIMER_TIMB_TIMEOUT); //触发 ADC 转换。 // ADCProcessorTrigger (ADC0_BASE、0); } int main (void) { //初始配置 SysCtlClockSet (SYSCTL_SYSDIV_1 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHz);//将时钟设置为直接从外部晶振/振荡器运行。 SysCtlPeripheralEnable (SYSCTL_Periph_GPIOD);//为中的模拟启用 GPIOD ROM_SysCtlPeripheralEnable (SYSCTL_Periph_TIMER0);//启用 Timer0 ROM_SysCtlDelay (1); //向量表 中的寄存器 timer0B 处理程序 IntRegister (INT_TIMER0B、Timer0BIntHandler); InitConsole ();//UART 配置 TimerConfigure (TIMER0_BASE、TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PERIODICRAY); TimerLoadSet (TIMER0_BASE、TIMER_B、SysCtlClockGet ()/ 1000); IntMasterEnable(); TimerIntEnable (TIMER0_BASE、TIMER_TIMB_TIMEOUT); IntEnable (INT_TIMER0B); G_ui32Counter = 0; TimerEnable (TIMER0_BASE,TIMER_B); //--------------- //GPIO 配置--> GPIOPinTypeADC (GPIO_PORTD_base、GPIO_PIN_0|GPIO_PIN_1);//将 PE2配置为模数输入 SysCtlPeripheralEnable (SYSCTL_Periph_ADC0);//启用 ADC0模块。 ADCSequenceConfigure (ADC0_BASE、0、ADC_TRIGGER_processor、0); ADCSequStepConfigure (ADC0_BASE、 0、0、ADC_CTL_CH6 /*| ADC_CTL_IE | ADC_CTL_END_/); ADCSequenceStepConfigure (ADC0_BASE、0、1、ADC_CTL_CH7 | ADC_CTL_IE | ADC_CTL_END); ADCSequenceEnable (ADC0_BASE、0); ADCIntClear (ADC0_BASE,0); //--------------- //Variables --> uint32_t CHANNELS[8];//ADC 数组->大小与 FIFO 深度相同 uint32_t ui32PrevCount = 0;//计时器 uint32_t PD0; uint32_t PD1; while (1) { while (!ADCIntStatus (ADC0_BASE、0、false)){}//如果样本准备就绪、则让 UART 显示值 、而(!ADCIntStatus (ADC0_BASE、0、false)){}//如果样本准备就绪、则让 UART 显示值 ADCIntClear (ADC0_BASE、0); ADCSequenceDataGet (ADC0_BASE、0、CHANNELS); PD0=通道[1]; PD1 =通道[0]; UARTprintf ("%4D\r"、PD0); UARTprintf ("\n"); ui32PrevCount = g_ui32Counter;//!important } }
非常感谢! 遗憾的是、在您设置 ADC 的方式方面、我没有看到任何重大差异。 由于某种原因、当我扫描一个通道(PD_2)时、我会得到我期望的值、但当我扫描两个通道(PD_2和 PD_1)时、PD_2的值完全不同。
我尝试使用这两个通道测量有刷直流电机的电流和电压、以便能够估算电机的功耗。
我附上了我的代码、希望有人能够提供帮助。
#include //std INT (uint8_t、uint16_t 等)
#include "driverlib/adc.h"
#include "driverlib/pwm.h"
#include "driverlib/QEI.h"
#include "driverlib/sysctl.h"
#include "usbprint.h"
//
// ADC 样本数(在微控制器上运行 RAM 之前~最大值)
//需要为串行打印语句保留一定数量的 RAM
//否则打印语句失败。
//
#define NUM_SAples 3000
//
// 20kHz 信号的时钟节拍数(时钟以80MHz -> 4000节拍运行)
//
#define PWM_PERIOD_80KHZ F_CPU / 80000 //(80MHz/80000 -> 1000个周期)
#define PWM_PERIOD_40kHz F_CPU / 40000 //(80MHz/40000 -> 2000个周期)
#define PWM_PERIOD_20kHz F_CPU / 20000 //(80MHz / 20000 -> 4000个周期)
#define PWM_PERIOD_10kHz F_CPU / 10000 //(80MHz/10000 -> 8000个周期)
#define PWM_PERIOD_5kHz F_CPU / 5000 //(80MHz/5000 -> 16000个周期)
#define PWM_PERIOD_2kHz F_CPU / 2000 //(80MHz/2000 -> 40000个周期)
//
//指定捕捉每个编码器速度值的速度(以秒为单位)
//针对编码器的 TIMESTEP
//
//编码器为12位分辨率,因此每转有4096个计数。
//齿轮箱的减排量为~9.96154:1(35*37)/(13*10)。
//电机转轴应以~25Hz 的频率运行。
//
#define ENC_TIMESTEP_S 0.001
//
//全局变量:
//
//
//为 CH4的单端 ADC 结果分配时间(微秒)
//(PD_3)(12位 ADC 计数)、CH5上的单端 ADC 结果
//(PD_2)(12位 ADC 计数)和正交编码器结果(节拍率
//编码器时间步长)。
//
uint32_t ADC_TIME_BUFFER[NUM_SAMESS]={0};
uint16_t ADC_CH5_buffer[NUM_Samples]={0};
uint16_t ADC_CH6_buffer[NUM_SAMESS]={0};
uint16_t QE_buffer[NUM_SAMESS]={0};
uint16_t ui16StepDelay_ms = 500;
uint16_t ui16PWMDutyCycle = PWM_PERIOD_20kHz/100;
const int ledPin = blue_LED;//PF_2
//
//
//此函数将 UART0设置为用于控制台显示信息
//因为示例正在运行。
//
//
空 initConsole (空)
{
//
//初始化控制台 I/O 的串行端口
//
Serial.begin(115200);
}
//
//
//此函数将 LED 引脚设置为用于显示状态信息
//作为示例运行的用户。
//
//
空 initLED (空)
{
//为输出配置 LED 引脚
引脚模式(ledPin、输出);
}
//
//
//此函数设置用于捕获读数的 ADC
//
//
void initadc (void)
{
//
//必须启用 ADC0外设才能使用。
//
//电机电流传感器 PD_2 (AIN5)
//电机电压传感器 PD_1 (AIN6)
SysCtlPeripheralEnable (SYSCTL_Periph_ADC0);
//
//对于此示例,ADC0与端口 E7/E6上的 AIN0/1一起使用。
//您使用的实际端口和引脚可能有所不同,请参阅
//数据表以了解更多信息。 需要启用 GPIO 端口 E
//因此可以使用这些引脚。
// TODO:将其更改为您正在使用的 GPIO 端口。
//
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOD);
//
//为这些引脚选择模拟 ADC 功能。
//请查阅数据表以查看每个引脚分配的函数。
// TODO:更改此选项以选择您正在使用的端口/引脚。
//
GPIOPinTypeADC (GPIO_PORTD_base、GPIO_PIN_2 | GPIO_PIN_1);
//GPIOPinTypeADC (GPIO_PORTD_BASE、GPIO_PIN_2);
//
//配置前需要禁用 ADC
//
ADCSequenceDisable (ADC0_BASE、2);
//
//使用处理器信号触发器启用采样序列2。 序列2
当处理器发送信号启动时、//将执行最多4个样本
//转换。 每个 ADC 模块有4个可编程序列、序列0
//至序列3。 此示例任意使用序列2。
//
ADCSequenceConfigure (ADC0_BASE、2、ADC_TRIGGER_PROCESSOR、0);
//
//设置触发器和序列开始之间的相位延迟
//如果触发在上升沿上的时间稍有不同,则会发生这种情况
//可以降低 ADC 信号中的噪声
//
//ADCPhaseDelaySet (ADC0_BASE、ADC_PHASE_0);
//
//在序列2上配置步骤0和步骤1。 对中的通道0 (ADC_CTL_CH0)进行采样
//差分模式(ADC_CTL_D)并配置中断标志
//(ADC_CTL_IE)将在采样完成时置1。 告诉 ADC 逻辑
//这是序列2上的最后一次转换(ADC_CTL_END)。 序列
// 3只有一个可编程步骤。 序列1和2有4个步骤、和
//序列0有8个可编程步骤。 因为我们正在进行两次转换
//使用序列2,我们将仅配置步骤0和步骤1。 了解详情
//有关 ADC 序列和步骤的信息、请参阅数据表。
//
ADCSequenceStepConfigure (ADC0_BASE、2、0、ADC_CTL_CH5 /*| ADC_CTL_IE /*| ADC_CTL_END*/);
ADCSequenceStepConfigure (ADC0_BASE、2、1、ADC_CTL_CH6 | ADC_CTL_IE | ADC_CTL_END);
//
//配置 ADC 的硬件过采样因子
//
//ADCHardwareOversampleConfigure (ADC0_BASE、64);
//
//由于采样序列2现在已配置,因此必须将其启用。
//
ADCSequenceEnable (ADC0_BASE、2);
//
//清除中断状态标志。 这样做是为了确保
//中断标志在我们进行采样之前被清除。
//
ADCIntClear (ADC0_BASE、2);
}
//
//
//此函数设置用于电机控制的 PWM
//
//
void initPWM (void)
{
//
//设置 PWM 模块
// Tiva Launchpad 有两个 PWM 模块(0和1)。 模块1涵盖 LED 引脚。
//必须启用 PWM0外设才能使用。
//
//在 PB_4上驱动脉宽调制信号
SysCtlPeripheralEnable (SYSCTL_Periph_PWM0);
//
//对于这个示例、PWM0与 PortB 引脚6一起使用。 实际端口
//和使用的引脚可能在您的器件上有所不同、请参阅的数据表
//更多信息。 GPIO 端口 B 需要启用、以便可以启用这些引脚
//已使用。
// TODO:将其更改为您正在使用的 GPIO 端口。
//
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOB);
//
//配置 GPIO 引脚复用以选择这些引脚的 PWM 功能。
//此步骤选择可用于这些引脚的替代功能。
//如果您的器件支持 GPIO 引脚功能多路复用、这是必需的。
//请查阅数据表以查看每个引脚分配的函数。
// TODO:更改此选项以选择您正在使用的端口/引脚。
//
GPIOPinConfigure (GPIO_PB4_M0PWM2);
//
//在引脚 PB6和 PB7上为 PWM 功能配置 GPIO 引脚。 请参阅
//数据表以查看每个引脚分配的函数。
// TODO:更改此选项以选择您正在使用的端口/引脚。
//
GPIOPinTypePWM (GPIO_PORTB_BASE、GPIO_PIN_4);
//
//配置 PWM 选项
//
PWMGenConfigure (PWM0_BASE、PWM_GEN_1、PWM_GEN_MODE_DOWN | PWM_GEN_MODE_NO_SYNC);
//
//启用 ADC 的触发器
//
//PWMGenIntTrigEnable (PWM0_BASE、PWM_GEN_1、PWM_TR_CNT_LOAD);
//
//将 PWM 周期设置为20kHz (电机驱动器的最大设置)
//
PWMGenPeriodSet (PWM0_BASE、PWM_GEN_1、PWM_PERIOD_20kHz);
//
//将 PWM 占空比设置为1%
//
PWMPulseWidthSet (PWM0_BASE、PWM_OUT_2、PWM_PERIOD_20kHz/100);
//
//启用 PWM0输出信号上的死区生成。 PWM 位0
//(PD0)将具有25%的占空比(在上面设置)、而 PWM 位1将具有该占空比
//占空比为75%。 这些信号之间将有10us 的间隙
//上升沿和下降沿。 这意味着、在 PWM 位1变为高电平之前、
// PWM 位0至少已处于低电平160个周期(或10us)、也是如此
//在 PWM 位0变为高电平之前。 死区发生器允许您指定
// PWM 之前"死区"延迟的宽度、以 PWM 时钟周期为单位
//信号在 PWM 信号下降后变为高电平。 在本示例中、我们
//将在的上升沿和下降沿使用160个周期(或10us)
// PD0。 有关死区的更多信息、请参阅数据表
//生成。
//
//PWMDeadBandEnable (PWM0_BASE、PWM_GEN_1、160、160);
//
//启用 PWM 发生器
//
PWMGenEnable (PWM0_BASE、PWM_GEN_1);
//
//打开输出引脚
//
PWMOutputState (PWM0_BASE、PWM_OUT_2_BIT、TRUE);
}
//
//
//此函数设置用于测量电机转速的 QEI
//
//
空 initQEI (空)
{
//
//设置 QEI 模块
// Tiva Launchpad 有两个 QEI 模块(0和1)。 模块0涵盖 LED 引脚。
//必须启用 QEI1外设才能使用。
//
SysCtlPeripheralEnable (SYSCTL_Periph_QEI1);
//
//对于此示例、QEI1与端口 C 引脚5和6一起使用。 实际端口
//和使用的引脚可能在您的器件上有所不同、请参阅的数据表
//更多信息。 GPIO 端口 C 需要启用、以便可以启用这些引脚
//已使用。
// TODO:将其更改为您正在使用的 GPIO 端口。
//
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOC);
//
//配置 GPIO 引脚复用以选择这些引脚的 PWM 功能。
//此步骤选择可用于这些引脚的替代功能。
//如果您的器件支持 GPIO 引脚功能多路复用、这是必需的。
//请查阅数据表以查看每个引脚分配的函数。
// TODO:更改此选项以选择您正在使用的端口/引脚。
//
GPIOPinConfigure (GPIO_PC5_PHA1);//GPIO_PC5_PHA1
GPIOPinConfigure (GPIO_PC6_PHB1);//GPIO_PC6_PHB1
//
//在引脚 PB6和 PB7上为 PWM 功能配置 GPIO 引脚。 请参阅
//数据表以查看每个引脚分配的函数。
// TODO:更改此选项以选择您正在使用的端口/引脚。
//
GPIOPinTypeQEI (GPIO_PORTC_BASE、GPIO_PIN_5 | GPIO_PIN_6);
//
// nEncoderTimerPeriod:用于配置 QEI (用于测量速度的时钟节拍数)
//
uint32_t nEncoderTimerPeriod_tick = F_CPU * ENC_TIMERSTEP_S;// 8000000000*0.001=80000
//
//配置和启用 QEI
//
QEIConfigure (QEI1_base、(QEI_CONFIG_CAPTURE_A_B | QEI_CONFIG_NO_RESET | QEI_CONFIG_QUIPOTIVATE | QEI_CONFIG_NO_SWaP)、UINT32_MAX);
//
//
//
QEIVelocityConfigure (QEI1_base、QEI_VELDIV_1、nEncoderTimerPeriod_tick);//除以时钟速度以获取计数/秒
//
//
//
QEIEnable (QEI1_BASE);
//
//
//
QEIVelocityEnable (QEI1_base);
}
//
//
//此函数以毫秒延迟使 LED 闪烁多次
//之间。
//
//
空 blinkLED (uint32_t ui32Times、uint32_t ui32Milliseconds)
{
//
//闪烁 LED
//
digitalWrite (ledPin、low);
for (int i = 0;i < ui32Times;i++){
digitalWrite (ledPin、HIGH);
延迟(ui32毫秒);
digitalWrite (ledPin、low);
延迟(ui32毫秒);
}
}
//
//
//此函数触发 ADC 转换并将 ADC 读数存储在中
//无符号整数的数组。
//
//
空 readadc (uint32_t * pui32ADCValues)
{
//
//触发 ADC 转换。
//
ADCProcessorTrigger (ADC0_BASE、2);
//
//等待转换完成。
//
while (!ADCIntStatus (ADC0_BASE、2、false))
{
}
//
//清除 ADC 中断标志。
//
ADCIntClear (ADC0_BASE、2);
//
//读取 ADC 值。
//
ADCSequenceDataGet (ADC0_BASE、2、pui32ADCValues);
}
//
//
//此函数记录 ADC 读数并将其存储在预分配的中
//缓冲器。
//
//
空记录 RawReadings (bool bRunMotorStepInput)
{
uint32_t pui32ADCValues[4];
//
//确定电机是否使用 STEP 输入运行
//对循环进行单独处理,以最大限度地提高循环内的速度/最大程度地减少计算
//
if (bRunMotorStepInput){
//
//设置脉宽占空比
//
PWMPulseWidthSet (PWM0_BASE、PWM_OUT_2、ui16PWMDutyCycle、tick);
延迟(ui16StepDelay_ms);//记录值之前的可选延迟
}
for (int i = 0;i < NUM_SAples;i++){
//
//读取 ADC 值
//
readadc (pui32ADCValues);
//
//存储时间和 ADC 值
//
adc_time_buffer[i]=微秒();
ADC_CH5_buffer[i]=(uint16_t) pui32ADCValues[0];
ADC_CH6_buffer[i]=(uint16_t) pui32ADCValues[1];
//
//如果电机正在运行,记录正交编码器值
//
if (bRunMotorStepInput){QE_buffer[i]=(uint16_t) QEIVelocityGet (QEI1_base);}
}
//
//将脉宽占空比设置为1%
//
if (bRunMotorStepInput){PWMPulseWidthSet (PWM0_BASE、PWM_OUT_2、PWM_PERIOD_20kHz/100);}
}
//
//
//此函数通过发送存储在缓冲区中的 ADC 值
//由 MATLAB 进行附加后处理的串行端口。
//
//
空 sendRawReadings (bool bIncludeQE)
{
if (bIncludeQE){
for (int i = 0;i < NUM_SAples;i++){
//
//打印时间(微秒)、CH5 (计数)、CH6 (计数)和
// QE (每个时间步长的节拍数)
//
USBprintf ("%.4U、%.4U、%.4U、%.4u)\n\r\n、adc_time_buffer[i]、adc_ch5_buffer[i]、
ADC_CH6_buffer[i]、QE_buffer[i]);
}
}否则{
for (int i = 0;i < NUM_SAples;i++){
//
//打印时间(微秒)、CH5 (计数)和 CH6 (计数)
//
USBprintf ("%.4U、%.4U、%.4U、0\n\r\n、ADC_TIME_BUFFER[i]、ADC_CH5_buffer[i]、
ADC_CH6_buffer[i]);
}
}
延迟(5);
//
//打印字符以指示数据结束
//
USBprintf ("e\n\r");
}
//
//
//此函数通过发送存储在缓冲区中的 ADC 值
//由 MATLAB 进行附加后处理的串行端口。
//
//
void sendRawReadingsLive (uint32_t ui32计数)
{
uint32_t pui32ADCValues[2];
uint32_t 总和[3];
uint32_t ui32StartTime = micros ();
//
//设置脉宽占空比
//
PWMPulseWidthSet (PWM0_BASE、PWM_OUT_2、ui16PWMDutyCycle、tick);
总和[0]=0;
总和[1]=0;
总和[2]=0;
延迟(ui16StepDelay_ms);
对于(int i = 0;i < ui32Counts;i++){
//
//读取 ADC 值
//
readadc (pui32ADCValues);
总和[0]+=(uint16_t) pui32ADCValues[0];//电机电流计数
总和[1]+=(uint16_t) pui32ADCValues[1];//电机电压计数
总和[2]+=(uint16_t) QEIVelocityGet (QEI1_base);
//
//打印时间(微秒)、CH0 (计数)、CH1 (计数)和
// QE (每个时间步长的节拍数)
//
//打印超过244个计数的总和
//
if (i % 244 ==243){
USBprintf ("%.5U、%.6U、%.6U、%.3U\n\r\n、micros ()-ui32StartTime、sum[0]、
总和[1]、总和[2]);
总和[0]=0;
总和[1]=0;
总和[2]=0;
}
}
//
//打印字符以指示数据结束
//
USBprintf ("e\n\r");
//
//将脉宽占空比设置为1%
//
PWMPulseWidthSet (PWM0_BASE、PWM_OUT_2、PWM_PERIOD_20kHz/100);
}
//
//
// setup()在微控制器上电开始时运行一次
//
//
void setup(){
//
//"大多数 ADC 控制逻辑以16MHz 的 ADC 时钟速率运行。 。
//内部 ADC 分频器自动配置为16MHz 运行
//当系统 XTAL 与 PLL 一起选择时由硬件选择。'
//
SysCtlClockSet (SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_16MHz);
//
//初始化所有必要的模块
//
initConsole();
initLED();
initadC();
initPWM();
initQEI();
//
//指示初始化完成
//
黑色 LED (3、200);
//
//等待串行终端
//
延迟(1000);
//
//显示菜单
//
displayMenu();
}
//
//
// loop()在设置后立即连续运行
//
//
void loop(){
//
//改为使用串行事件
//
}
//
//
//只要有新数据出现,就会发生串行事件
//硬件串行 RX。 此例程在每个例程之间运行
// time loop()运行,因此使用循环内的延迟可以延迟
//响应。 可能有多个字节的数据可用。
//
//
void serialEvent()
{
while (Serial.available ())
{
//解析串行数据
开关(Serial.Read())
{
案例77:案例109://'m'或'm'被按下以查看菜单
displayMenu();
中断;
判例76:判例108://'l'或'l'被按下以运行电机(打印输出不带缓冲器)
黑色 LED (3、200);
延迟(1000);
digitalWrite (ledPin、HIGH);
sendRawReadingsLive (Serial.parseInt());
digitalWrite (ledPin、low);
中断;
案例67:案例99://'c'或"C"被按下以校准 ADC
BlinkLED (3、200);//指示 ADC 校准开始
延迟(1000);//延迟一秒
digitalWrite (ledPin、HIGH);
记录读数(false);
sendRawReadings (假);
digitalWrite (ledPin、low);
中断;
案例68:案例100://'d'或'D'被按下以更改延迟
闪烁 LED (3、200);//指示开始
ui16StepDelay_ms = Serial.parseInt();
中断;
案例83:案例115:按下了//"S"或"S"以运行电机(打印输出带有缓冲器)
BlinkLED (3、200);//指示阶跃输入的开始
延迟(1000);//延迟一秒
digitalWrite (ledPin、HIGH);
RecordRawReadings (真);
sendRawReadings (真);
digitalWrite (ledPin、low);
中断;
案例82:案例114://'r'或'r'被按下以运行电机(不打印输出)
闪烁 LED (3、200);//指示开始
延迟(1000);//延迟一秒
digitalWrite (ledPin、HIGH);//打开 LED
//
//将脉宽占空比设置为所需的量
//
PWMPulseWidthSet (PWM0_BASE、PWM_OUT_2、ui16PWMDutyCycle、tick);
//
//等待所需的量(毫秒)
//
延迟(Serial.parseInt());
//
//将脉宽占空比设置回1%
//
PWMPulseWidthSet (PWM0_BASE、PWM_OUT_2、PWM_PERIOD_20kHz/100);
digitalWrite (ledPin、low);//关闭 LED
中断;
案例80:案例112://'p'或'p'被按下以改变 PWM 占空比
黑色 LED (3、200);
ui16PWMDutyCycle = Serial.parseInt();
中断;
判例81:判例113://'q'或'q'被按下以退出程序
//清理
USBprintStr ("程序结束。");
while (1){continue;}
中断;
}
delayMicroseconds (100);//等待足够的时间使新的串行数据可用
}
}
空显示菜单(空)
{
//控制器菜单
USBprintStr ("Pololu 电机校准菜单:\n\n");
USBprintStr ("c -发送 ADC 信号\n"\});
USBprintStr ("d -更改阶跃延迟(ms)\n"\};
USBprintStr ("l -运行电机(非缓冲打印输出)\n\n"\};
USBprintStr ("m -显示菜单\n\r\n);
USBprintStr ("p -更改 PWM 占空比(节拍数)\n"\};
USBprintStr ("s -运行电机(缓冲打印输出)\n"\};
USBprintStr ("r -运行电机(无打印输出)\n"\};
USBprintStr ("q - Quit\n"r);
}
您好、
我认为你遇到的问题与我遇到的问题相同。 您为 pui32ADCValues[2]提供了错误的大小。
由于您使用的是序列发生器2、因此它需要一个由4个位置组成的数组"pui32ADCValues[4]"、一旦此序列发生器选择了 FIFO 的 DE 深度、在本例中也是4。 然后、您必须将以下内容放置:
while (!ADCIntStatus (ADC0_BASE、2、false))
{
}您使用的信道数量相同。 因此、如果您仅使用两个通道、就会出现这种情况:
int main () { uint32_t pui32ADCValues[4]; uint32_t PD1; uint32_t PD2; while (1) { while (!ADCIntStatus (ADC0_BASE、2、false)) { } while (!ADCIntStatus (ADC0_BASE、2、false)) { } ADCIntClear (ADC0_BASE、2); ADCSequenceDataGet (ADC0_BASE、2、pui32ADC0Value); PD1= pui32ADC0Value[0]; PD2= pui32ADC0Value[1]; }
此外、您的代码太多、请尝试将其删除一段时间、 然后首先修复此 ADC 问题。 另一件事是查看通道是否配置正确,一旦使用 PD1和 PD2,则必须分别使用通道 CH6和 CH5。
感谢您的建议!
但结果仍然相同。
基本上、我注意到一个通道仍然受到另一个通道的影响。 下面是我已经处理过的几种情形:
通道1、通道2
GND、GND -当两者都接地时、它们都寄存器中的值约为0 (良好)
GND、1.5V -当应用此值时、CH1寄存器大约为10个计数、CH2寄存器大约为2000 (即 CH1被 CH2上拉)
GND、3V -当应用此值时、CH1寄存器大约20次计数、CH2寄存器大约4000次(即 CH1被进一步上拉、似乎与 CH2具有线性关系)
我注意到、当不进行硬件过采样时、这种关系要强得多、因此采样通道之间似乎需要稳定时间。 我尝试以极快的速度(每通道500kSPS)进行采样。 基本上、当硬件采样被启用并且大(64)时、它需要64个 CH1采样将其放置在 FIFO 插槽1中、然后将64个 CH2采样放置到 FIFO 插槽2中、因此后64个采样是整个64微秒后的结果。 (这都是假设我正确理解)。 这就是我认为需要进行某种稳定时间的原因。 随着我减少硬件采样、从而缩短采样 CH1和 CH2之间的时间、情况变得更糟。
我知道在用于输入多路复用的其他 ADC 芯片上、需要一些时间来切换通道、我想知道这种情况是否也是这样?
另外、我查看了 TM4C123GH6PM 数据表的 ADC 部分、并注意到了关于抖动位的部分(第806页)。 想知道是否需要设置该参数? 我尝试设置它、但似乎没有改变。
最后、我想知道此应用是否需要更实质性的上拉或下拉电阻器? 我对这件事不是很了解、只是想猜测我可以做些什么来解决这个问题。
再次感谢您的见解! 我希望有人能够引导我朝着正确的方向前进。