本帖最后由 Peixu 于 2024-12-4 15:21 编辑
1. VGA信号的基本概念 VGA信号包括三个主要部分: [size=10.5000pt] **RGB信号**:分别代表红色、绿色和蓝色的模拟信号,这些信号的电平决定了显示图像的颜色。 [size=10.5000pt] **水平同步信号(HSYNC)**:在每行像素结束时,提供一个短脉冲信号,指示显示设备开始新的一行。 [size=10.5000pt] **垂直同步信号(VSYNC)**:在一帧结束时提供脉冲信号,指示显示设备开始新的一帧。 对于1920x1080分辨率的60Hz显示,VGA信号的有效采样时间和采样率计算如下: [size=10.5000pt] 每行有效像素时间为12.92微秒。 [size=10.5000pt] 每行采集的像素为40个,因此每个像素的采样时间为323纳秒。 [size=10.5000pt] 所以在我们在这12.82us的时间尽可能用ADC去多采集信号。这样才能达到更好的效果。
2. 设计思路 要实现VGA信号的ADC采集,主要步骤如下: [size=10.5000pt] **信号处理**:通过电路设计,将VGA信号的RGB信号和同步信号连接到APM32F4的ADC引脚,并进行必要的电平转换。 [size=10.5000pt] **ADC配置**:设置APM32F4的ADC参数,以便进行高速采样。 [size=10.5000pt] **DMA配置**:为了提高数据传输的效率,将ADC采集的数据通过DMA(直接存储器访问)方式传送至内存。 [size=10.5000pt] **外部中断处理**:使用外部中断来触发ADC采集,以确保在每个HSYNC信号到来时进行采样。 [size=10.5000pt] **数据处理**:在主循环中处理采集的数据,进行显示或存储。
3. 硬件连接 3.1 信号连接 将VGA信号的RGB信号和同步信号连接至APM32F4的ADC引脚和外部中断引脚: [size=10.5000pt] **R信号**:连接至ADC通道0(PA3)。 [size=10.5000pt] **G信号**:连接至ADC通道1(PA4)。 [size=10.5000pt] **B信号**:连接至ADC通道2(PA5)。 [size=10.5000pt] **HSYNC信号**:连接至外部中断(PC10)。 [size=10.5000pt] **VSYNC信号**:连接至另一个外部中断(PC11)。
3.2 电路设计 在连接VGA信号和APM32F4之间,建议使用以下电路设计: [size=10.5000pt] **低通滤波器**:在ADC输入引脚前添加低通滤波器,以减少高频干扰。 [size=10.5000pt] **电平转换电路**:确保输入信号在APM32F4的ADC输入范围内(通常是0-3.3V)。
4. 软件实现 4.1 ADC初始化 配置ADC以采集RGB信号: void ADC_Init(void) {
GPIO_Config_T gpioConfig;
ADC_Config_T adcConfig;
ADC_CommonConfig_T adcCommonConfig;
RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA);
// GPIO配置
GPIO_ConfigStructInit(&gpioConfig);
gpioConfig.mode = GPIO_MODE_AN;
gpioConfig.pupd = GPIO_PUPD_NOPULL;
gpioConfig.pin = GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5;
GPIO_Config(GPIOA, &gpioConfig);
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);
ADC_Reset();
// ADC通用配置
adcCommonConfig.mode = ADC_MODE_INDEPENDENT;
adcCommonConfig.prescaler = ADC_PRESCALER_DIV2;
ADC_CommonConfig(&adcCommonConfig);
// ADC配置
adcConfig.resolution = ADC_RESOLUTION_12BIT;
adcConfig.scanConvMode = DISABLE; // 单通道
adcConfig.continuousConvMode = ENABLE; // 连续模式
adcConfig.dataAlign = ADC_DATA_ALIGN_RIGHT;
adcConfig.extTrigEdge = ADC_EXT_TRIG_EDGE_FALLING;
adcConfig.extTrigConv = ADC_EXT_TRIG_CONV_EINT_11; // 触发方式为外部中断
adcConfig.nbrOfChannel = 1;
ADC_Config(ADC1, &adcConfig);
// 配置ADC通道
ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_3, 1, ADC_SAMPLETIME_3CYCLES); // R
ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_4, 1, ADC_SAMPLETIME_3CYCLES); // G
ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_5, 1, ADC_SAMPLETIME_3CYCLES); // B
}
4.2 DMA初始化为ADC配置DMA:
void DMA_Init(void)
{
DMA_Config_T dmaConfig;
RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_DMA2);
dmaConfig.peripheralBaseAddr = ADC_DR_ADDR;
dmaConfig.memoryBaseAddr = (uint32_t)R[0]; // 初始地址指向第一行
dmaConfig.dir = DMA_DIR_PERIPHERALTOMEMORY;
dmaConfig.bufferSize = SAMPLES_PER_CHANNEL; // 每次传输的数据量
dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
dmaConfig.memoryInc = DMA_MEMORY_INC_ENABLE;
dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_HALFWORD;
dmaConfig.memoryDataSize = DMA_MEMORY_DATA_SIZE_HALFWORD;
dmaConfig.loopMode = DMA_MODE_CIRCULAR; // 使用普通模式
dmaConfig.priority = DMA_PRIORITY_HIGH;
dmaConfig.fifoMode = DMA_FIFOMODE_DISABLE;
dmaConfig.fifoThreshold = DMA_FIFOTHRESHOLD_HALFFULL;
dmaConfig.memoryBurst = DMA_MEMORYBURST_SINGLE;
dmaConfig.peripheralBurst = DMA_PERIPHERALBURST_SINGLE;
dmaConfig.channel = DMA_CHANNEL_0;
DMA_Config(DMA2_Stream0, &dmaConfig);
DMA_EnableInterrupt(DMA2_Stream0, DMA_INT_TCI**); // 开启传输完成中断
DMA_Enable(DMA2_Stream0); // 启用 DMA
}
4.3 外部中断处理使用外部中断处理HSYNC信号:
void EINT15_10_IRQHandler(void) {
if (EINT_ReadIntFlag(EINT_LINE_10)) {
/* 启动 ADC DMA 采集 */
ADC1->STS = ~(uint32_t)ADC_FLAG_OVR;
ADC1->CTRL2_B.REGSWSC = BIT_SET;
while(RESET == DMA_ReadStatusFlag(DMA2_Stream0, DMA_FLAG_TCI**0));
DMA_ClearStatusFlag(DMA2_Stream0, DMA_FLAG_TCI**0);
DMA2_Stream0->SCFG_B.EN = DISABLE;
dmaCompleteFlag = 1;
HSync_cnt ++;
currentRow++; // 切换到下一行 //
if (currentRow >= HSync_MAX)
{
currentRow = 0; // 重置行号
}
DMA_ClearIntFlag(DMA2_Stream0, DMA_INT_TCI**0);
DMA_Switch(currentChannel,currentRow);
EINT_ClearIntFlag(EINT_LINE_10);
}
if (EINT_ReadIntFlag(EINT_LINE_11)) {
currentChannel++;
if (currentChannel >= 3) currentChannel = 0; // 切换通道
ADC_SwitchChannel(currentChannel);
EINT_ClearIntFlag(EINT_LINE_11);
}
}
4.4 数据处理在主循环中,处理采集到的数据:
int main(void) {
// 初始化相关模块
USART_Init();
ADC_Init();
DMA_Init();
APM_PBInit(BUTTON_KEY2, BUTTON_MODE_EINT); //中断行 PC10
APM_PBInit(BUTTON_KEY1, BUTTON_MODE_EINT); //中断场 PC11
while (1) {
if (dmaCompleteFlag)
{
dmaCompleteFlag = 0;
/* 处理采集到的数据 */
if (currentChannel == 0){
for (uint16_t row = 0; row < HSync_MAX; row++)
{
for (uint16_t i = 0; i < SAMPLES_PER_CHANNEL; i++)
{
printf("R[%d][%d] %d\r\n", row,i, R[row][i]);
}
}
}
if (currentChannel == 1){
}
if (currentChannel == 2){
}
printf("\r\n");
}
}
}
通过上述步骤,可以成功地使用APM32F4微控制器采集VGA信号。具体的使用可能需要根据特定需求对代码进行适当的修改和优化,以实现更好的性能和数据处理能力。通过采集VGA信号,可以为后续的图像处理、显示和分析提供数据支持。希望本方案能为您的项目提供参考和借鉴。
|