4.A/D数据采集
在开发板上,没有配置常规的按键,取而代之的则是一个方向键,并以模拟信号的方式来进行识别,其电路见图16所示。
由图可知,该方向键所使用的硬件为PA8,是A/D检测的8#通道。此外,它还给出了各键作用下的电压检测值,以供对比分析,见红色框内的内容。

图16 方向键电路
它之所以这样设计,可有效地解决引脚资源占用过多的问题,也为A/D检测提供了硬件方面的方便。
有了硬件的支持,那软件呢?
对不起,在例程方面没有提供相应的支持。
现在,OLED屏的作用又可以派上用场了,借助它可以观察程序设计的正确性。
经反复的探索和尝试,终于有了可信的结果。
其中,A/D的初始化函数为:
static void MX_ADC1_Init(void)
{
LL_ADC_InitTypeDef ADC_InitStruct = {0};
LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_SYSCLK);
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC);
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
GPIO_InitStruct.Pin = LL_GPIO_PIN_8;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
#define ADC_CHANNEL_CONF_RDY_TIMEOUT_MS ( 1U)
#if (USE_TIMEOUT == 1)
uint32_t Timeout ;
#endif
ADC_InitStruct.Clock = LL_ADC_CLOCK_SYNC_PCLK_DIV4;
ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;
ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;
LL_ADC_Init(ADC1, &ADC_InitStruct);
LL_ADC_REG_SetSequencerConfigurable(ADC1, LL_ADC_REG_SEQ_FIXED);
ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;
ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE;
ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_NONE;
ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN;
LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
LL_ADC_REG_SetSequencerScanDirection(ADC1, LL_ADC_REG_SEQ_SCAN_DIR_FORWARD);
LL_ADC_SetOverSamplingScope(ADC1, LL_ADC_OVS_DISABLE);
LL_ADC_SetTriggerFrequencyMode(ADC1, LL_ADC_CLOCK_FREQ_MODE_HIGH);
LL_ADC_REG_SetSequencerChAdd(ADC1, LL_ADC_CHANNEL_8); //LL_ADC_CHANNEL_4
#if (USE_TIMEOUT == 1)
Timeout = ADC_CHANNEL_CONF_RDY_TIMEOUT_MS;
#endif /* USE_TIMEOUT */
while (LL_ADC_IsActiveFlag_CCRDY(ADC1) == 0)
{
#if (USE_TIMEOUT == 1)
if (LL_SYSTICK_IsActiveCounterFlag())
{
if(Timeout-- == 0)
{
Error_Handler();
}
}
#endif
}
LL_ADC_ClearFlag_CCRDY(ADC1);
LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_1, LL_ADC_SAMPLINGTIME_79CYCLES_5);
LL_ADC_DisableIT_EOC(ADC1);
LL_ADC_DisableIT_EOS(ADC1);
LL_ADC_EnableInternalRegulator(ADC1);
uint32_t wait_loop_index;
wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
while(wait_loop_index != 0)
{
wait_loop_index--;
}
LL_ADC_EnableIT_EOC(ADC1);
LL_ADC_EnableIT_OVR(ADC1);
}激活A/D采集的函数为:
void ADC_Activate(void)
{
__IO uint32_t wait_loop_index = 0U;
__IO uint32_t backup_setting_adc_dma_transfer = 0U;
#if (USE_TIMEOUT == 1)
uint32_t Timeout = 0U;
#endif
if (LL_ADC_IsEnabled(ADC1) == 0)
{
LL_ADC_EnableInternalRegulator(ADC1);
wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
while(wait_loop_index != 0)
{
wait_loop_index--;
}
backup_setting_adc_dma_transfer = LL_ADC_REG_GetDMATransfer(ADC1);
LL_ADC_REG_SetDMATransfer(ADC1, LL_ADC_REG_DMA_TRANSFER_NONE);
LL_ADC_StartCalibration(ADC1);
#if (USE_TIMEOUT == 1)
Timeout = ADC_CALIBRATION_TIMEOUT_MS;
#endif
while (LL_ADC_IsCalibrationOnGoing(ADC1) != 0)
{
#if (USE_TIMEOUT == 1)
if (LL_SYSTICK_IsActiveCounterFlag())
{
if(Timeout-- == 0)
{
Error_Handler();
}
}
#endif
}
LL_ADC_REG_SetDMATransfer(ADC1, backup_setting_adc_dma_transfer);
wait_loop_index = (ADC_DELAY_CALIB_ENABLE_CPU_CYCLES >> 1);
while(wait_loop_index != 0)
{
wait_loop_index--;
}
LL_ADC_Enable(ADC1);
#if (USE_TIMEOUT == 1)
Timeout = ADC_ENABLE_TIMEOUT_MS;
#endif
while (LL_ADC_IsActiveFlag_ADRDY(ADC1) == 0)
{
#if (USE_TIMEOUT == 1)
if (LL_SYSTICK_IsActiveCounterFlag())
{
if(Timeout-- == 0)
{
Error_Handler();
}
}
#endif
}
}
}实现A/D采集和显示的主程序为:
int main(void)
{
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
NVIC_SetPriority(SysTick_IRQn, 3);
SystemClock_Config();
MX_GPIO_Init();
OLED_config();
OLED_Init();
OLED_Clear();
OLED_ShowString(0,0," STM32C0116_DK",16);
OLED_ShowString(0,2," U = mv",16);
OLED_ShowString(0,4," A/D= ",16);
MX_ADC1_Init();
ADC_Activate();
while (1)
{
ConversionStartPoll_ADC_GrpRegular();
uhADCxConvertedData = LL_ADC_REG_ReadConversionData32(ADC1);
uhADCxConvertedData_Voltage_mVolt = __LL_ADC_CALC_DATA_TO_VOLTAGE(VDDA_APPLI, uhADCxConvertedData, LL_ADC_RESOLUTION_12B);
OLED_ShowNum(48,4, uhADCxConvertedData,4,16);
OLED_ShowNum(48,2, uhADCxConvertedData_Voltage_mVolt,4,16);
LED_On();
LL_mDelay(LED_BLINK_SLOW);
LED_Off();
LL_mDelay(LED_BLINK_SLOW);
}
}经程序的编译和下载,其测试结果见图17至图22所示,经与图16的电压输出值的比对,说明其结果正确。

图17 悬空状态

图18 按选取键

图19 按向左键

图20 按向下键

图21 按向上键

图22 按向右键
下面将重点解决串口通信的问题,以实现最终的目标。
我要赚赏金
