百万访问 · 744 篇原创|写给同道中人的一段 优快云 记录

百万访问 · 744 篇原创|写给同道中人的一段 优快云 记录

在 优快云 持续写作这些年,我留下了这样一组数字:

744 篇原创技术博文,累计访问量 100 万+,粉丝 5,453(5K+)。

它们并不是某一两篇文章的偶然爆发,而是多年持续输出的自然累积。

我更愿意把这里,当作一个技术人员的长期记录空间。
不追热点、不拼噱头,只是把在工作中、项目中、学习中真正走过的路,系统地整理下来。

目前内容主要以专栏形式持续更新,覆盖 Linux / 内核、Yocto、NVIDIA、AI、C/C++、嵌入式硬件与 BSP、安全等多个方向。它们共同指向同一个目标:

让技术变得清晰、可积累、可复用。

这些文章,更多是写给同行、工程师、技术人员看的。
也许不够热闹,但希望足够真实、足够踏实。

如果你同样长期在嵌入式、Linux 或系统底层方向深耕,
如果你也相信技术需要时间沉淀,

欢迎关注,也欢迎交流。

感谢每一位认真阅读、留言、讨论的同道中人。

<think>好的,我现在要解决用户的问题:如何基于GD32L235芯片使用ADC通过中断连续读取5个通道的值。用户需要示例代码和实现方法。首先,我需要回顾GD32L235的ADC模块特性,以及中断和DMA的相关配置。 首先,GD32L235的ADC支持多通道转换,可以使用扫描模式。用户需要连续读取5个通道,这意味着可能需要循环扫描这些通道。使用中断的话,每次转换完成都会触发中断,但需要注意中断频率和性能影响。 接下来,考虑ADC的工作模式。连续转换模式可能适合,这样ADC在完成一次扫描后会自动重新开始。但需要配置DMA吗?用户特别提到使用中断,所以可能不使用DMA,而是通过中断逐个读取每个通道的数据。不过,GD32L235的ADC是否支持在扫描多个通道后产生一个中断?或者每个通道转换完成后都会触发中断?这需要查阅手册。 根据GD32系列的一般特性,ADC扫描模式会在完成整个序列转换后触发EOC(转换结束)中断。因此,配置扫描模式,设置5个通道的转换序列,然后使能EOC中断,在中断中读取所有通道的数据。这样,每次扫描完成后,中断处理函数可以读取ADC的数据寄存器,存储到数组中。 然后,需要初始化ADC,配置通道的转换顺序,设置扫描模式和连续转换模式,使能中断,并启动ADC转换。同时,需要配置GPIO为模拟输入模式,确保对应的引脚正确。 另外,GD32的库函数可能与STM32有所不同,需要参考GD32L235的标准外设库文档。例如,ADC_Init结构体的配置,中断处理函数的编写,以及NVIC的配置。 可能的步骤: 1. 配置ADC GPIO引脚为模拟输入。 2. 初始化ADC,设置扫描模式、连续转换,设置转换通道数和顺序。 3. 配置ADC中断,使能EOC中断,设置NVIC。 4. 在中断服务函数中读取转换结果,并重新启动转换或处理数据。 5. 启动ADC转换。 需要注意的地方:在扫描模式下,转换结果寄存器只有一个,所以需要及时读取每个通道的数据,或者在多通道情况下,可能需要使用DMA来传输数据,否则在中断中逐个读取可能有问题。但用户明确要求使用中断而不是DMA,所以可能需要使用扫描模式,并在每次扫描完成后读取所有通道的数据。但GD32L235的ADC是否支持在扫描完成后触发中断?需要确认。 例如,在STM32中,扫描模式配合DMA可以自动传输多通道数据,而如果使用中断,可能需要在每个通道转换完成后触发中断,这会导致频繁中断。但GD32可能有所不同。根据GD32的参考手册,扫描模式下,当整个序列转换完成后,EOC标志会被置位,此时触发中断。因此,在中断中可以读取所有5个通道的数据,但如何读取每个通道的数据呢?可能需要使用规则组通道的数据寄存器,每个通道的结果是按顺序存储在同一个寄存器中的吗?或者需要配置多通道扫描后,每个通道的数据存储在对应的寄存器中? 可能的情况是,在扫描模式下,每个通道转换完成后,数据会被存储在同一个数据寄存器中,因此需要在每个通道转换时读取。但这样可能需要每个通道转换都触发中断,这会增加中断频率。或者,在扫描模式下,只有整个序列完成后才触发一次中断,此时可以通过读取数据寄存器多次来获取各个通道的值。这需要确认GD32L235的ADC数据寄存器结构。 查阅GD32L235的参考手册,假设其ADC规则组转换完成后,每个通道的结果会依次存储在ADC_RDATA寄存器中,或者需要通过读取不同的数据寄存器。或者,在扫描模式下,需要逐个通道读取,比如在中断中循环读取每个通道的结果。不过这可能不太对。 另一种方法是使用注入组,但规则组更常用。可能需要在扫描模式中配置5个通道,然后每次扫描完成后触发中断,在中断中读取所有5个通道的数据。但GD32的ADC可能需要在每个通道转换后手动读取数据,或者在扫描结束后自动存储到多个数据寄存器中? 假设GD32L235的ADC在扫描模式下,转换完整个序列后触发一次中断,此时用户需要读取每个通道对应的数据寄存器。例如,规则通道1的数据放在ADC_RDATA寄存器,但需要按顺序转换并存储。或者,是否有一个数据寄存器,每次转换后数据被覆盖,因此必须使用DMA来捕获每个通道的结果? 这里可能存在误解,如果使用扫描模式而不使用DMA,那么每次转换完成后数据寄存器会被覆盖,因此必须在每个通道转换后读取数据。但这样就需要每个通道转换后触发中断,导致高频率的中断,这可能影响系统性能。因此,更好的做法是使用DMA来传输多通道数据,但用户明确要求使用中断,所以只能接受每个通道转换后触发中断,或者在扫描完成后触发一次中断,此时读取所有通道的数据。 需要确认GD32L235的ADC是否支持在扫描模式完成后触发中断。例如,在规则组转换完成后触发EOC中断。如果是这样,那么在中断中可以读取各个通道的数据。但如何确定每个通道对应的数据存储位置? 可能的情况是,在扫描模式下,规则通道的转换按顺序进行,每次转换后数据存储在ADC_RDATA寄存器中,并且当所有通道转换完成后触发EOC中断。但这样的话,用户需要在每个通道转换时读取数据,或者只能在最后读取最后一个通道的数据。这显然有问题。 这可能需要使用DMA,因为DMA可以在每个通道转换后自动将数据转移到内存中的数组。但用户要求使用中断,所以可能需要另一种方法。 或者,GD32L235的ADC规则组有一个多通道扫描模式,并且当每个通道转换完成时触发EOC中断,但这样每个通道都会触发中断,导致频繁中断,但用户需要连续读取5个通道,所以可能需要在这种情况下处理。 例如,配置ADC为扫描模式,连续转换,使能EOC中断。然后,在中断服务程序中读取当前转换的通道数据,并记录到数组中。每次中断对应一个通道的转换完成。然后,在完成所有5个通道后,可以处理数据或重新启动转换。 但这种方法需要知道当前转换的是哪个通道,以便正确存储数据。GD32的ADC是否提供当前转换的通道号?或者需要用户自己跟踪通道顺序。 例如,配置规则通道序列为CH0, CH1, CH2, CH3, CH4,按顺序转换。当每个通道转换完成时触发中断,在中断中读取ADC_RDATA,并存储到数组的相应位置。例如,第一个中断对应CH0,第二个对应CH1,以此类推。但如何知道当前中断对应哪个通道呢? 可能没有直接的寄存器可以读取当前转换的通道,因此需要用户自己维护一个索引变量,在每次中断时递增,直到5个通道完成,然后重置索引。这种方法可能可行,但需要确保中断的触发和索引的同步。 例如,初始化时设置当前通道索引为0,在中断中读取数据并存储到数组[current_index],然后current_index++,当current_index达到5时,表示完成一轮转换,进行处理,并重置current_index为0。同时,ADC需要配置为连续转换模式,这样在完成一轮后会自动开始下一轮。 这种方法虽然可行,但需要处理中断的频繁触发,每个通道转换都会触发中断,可能影响系统实时性。但对于5个通道来说,如果ADC采样率不是特别高,可能可以接受。 现在,我需要根据GD32L235的库函数来编写代码示例。假设使用标准外设库,步骤大致如下: 1. 配置ADC的GPIO引脚为模拟输入,例如PA0-PA4对应通道0-4。 2. 初始化ADC,设置扫描模式、连续转换、使能EOC中断。 3. 配置规则组通道,设置转换顺序和采样时间。 4. 配置ADC中断,使能EOC中断,并设置NVIC。 5. 启动ADC转换。 6. 在中断服务函数中读取数据,并管理索引。 例如,代码的大致结构: ```c #include "gd32l23x.h" #define ADC_CHANNEL_COUNT 5 uint16_t adc_values[ADC_CHANNEL_COUNT]; volatile uint8_t adc_index = 0; void ADC_IRQHandler(void) { if(adc_interrupt_flag_get(ADC_INT_FLAG_EOC)) { adc_interrupt_flag_clear(ADC_INT_FLAG_EOC); adc_values[adc_index] = adc_regular_data_read(); adc_index++; if(adc_index >= ADC_CHANNEL_COUNT) { adc_index = 0; // 处理数据或通知主循环 } } } void adc_config(void) { rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_ADC); gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_MAX, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4); adc_deinit(); adc_mode_config(ADC_MODE_FREE); adc_special_function_config(ADC_CONTINUOUS_MODE, ENABLE); adc_data_alignment_config(ADC_DATAALIGN_RIGHT); adc_channel_length_config(ADC_REGULAR_CHANNEL, ADC_CHANNEL_COUNT); adc_regular_channel_config(0, ADC_CHANNEL_0, ADC_SAMPLETIME_55POINT5); adc_regular_channel_config(1, ADC_CHANNEL_1, ADC_SAMPLETIME_55POINT5); adc_regular_channel_config(2, ADC_CHANNEL_2, ADC_SAMPLETIME_55POINT5); adc_regular_channel_config(3, ADC_CHANNEL_3, ADC_SAMPLETIME_55POINT5); adc_regular_channel_config(4, ADC_CHANNEL_4, ADC_SAMPLETIME_55POINT5); adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE); adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE); adc_interrupt_enable(ADC_INT_EOC); nvic_irq_enable(ADC_IRQn, 0, 0); adc_enable(); delay_1ms(1); adc_calibration_enable(); adc_software_trigger_enable(ADC_REGULAR_CHANNEL); } int main(void) { adc_config(); while(1) { // 主循环中处理数据或进入低功耗模式 } } ``` 需要注意的是,上述代码可能需要根据GD32L235的具体库函数进行调整。例如,ADC中断标志的清除、通道配置函数是否正确,以及触发源的设置是否正确。例如,是否应该禁用外部触发,使用软件触发或自动连续转换。 另外,在连续转换模式下,可能不需要每次手动触发转换,而是启动后自动连续运行。因此,在初始化后调用adc_software_trigger_enable可能只需要一次,或者需要其他配置。 还需要确认ADC的中断服务函数名称是否正确,GD32L235的ADC中断名称可能为ADC_IRQHandler或其他名称,需参考启动文件或库文档。 此外,采样时间的设置需要根据实际需求调整,例如ADC_SAMPLETIME_55POINT5表示55.5个时钟周期的采样时间。 总结:用户需要的是使用中断连续读取5个通道的值,因此配置ADC为扫描模式,连续转换,每个通道转换完成后触发中断,在中断中读取数据并存储到数组,直到所有通道完成一轮转换。然后处理数据或开始下一轮。 可能还需要考虑数据对齐方式、校准、时钟配置等细节。例如,确保ADC时钟频率在允许范围内,进行校准以提高精度。 最后,在中断中处理完所有通道后,可能需要通知主程序数据已准备好,可以通过标志位或全局变量实现。</think>### GD32L235 ADC多通道中断采样实现步骤 #### 1. 硬件配置 - **MCU**: GD32L235系列 - **ADC通道**: 选择5个模拟输入通道(如`ADC_CHANNEL_0`至`ADC_CHANNEL_4`) - **GPIO配置**: 相关引脚需设置为模拟输入模式 #### 2. 初始化流程 ```c #include "gd32l23x.h" #define ADC_CHANNEL_NUM 5 volatile uint16_t adc_values[ADC_CHANNEL_NUM]; // 存储采样值 volatile uint8_t adc_index = 0; // 当前通道索引 void ADC_Config(void) { // 1. 使能时钟 rcu_periph_clock_enable(RCU_GPIOA); // 假设使用PA0-PA4 rcu_periph_clock_enable(RCU_ADC); // 2. 配置GPIO为模拟输入 gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4); // 3. ADC基础配置 adc_deinit(); adc_mode_config(ADC_MODE_FREE); // 独立模式 adc_special_function_config(ADC_CONTINUOUS_MODE, ENABLE); // 连续转换 adc_data_alignment_config(ADC_DATAALIGN_RIGHT); // 数据右对齐 // 4. 配置规则组通道 adc_channel_length_config(ADC_REGULAR_CHANNEL, ADC_CHANNEL_NUM); adc_regular_channel_config(0, ADC_CHANNEL_0, ADC_SAMPLETIME_55POINT5); adc_regular_channel_config(1, ADC_CHANNEL_1, ADC_SAMPLETIME_55POINT5); adc_regular_channel_config(2, ADC_CHANNEL_2, ADC_SAMPLETIME_55POINT5); adc_regular_channel_config(3, ADC_CHANNEL_3, ADC_SAMPLETIME_55POINT5); adc_regular_channel_config(4, ADC_CHANNEL_4, ADC_SAMPLETIME_55POINT5); // 5. 中断配置 adc_interrupt_enable(ADC_INT_EOC); // 使能转换完成中断 nvic_irq_enable(ADC_IRQn, 0, 0); // 使能NVIC // 6. 校准并启动ADC adc_enable(); delay_ms(1); // 等待ADC稳定 adc_calibration_enable(); // 执行校准 adc_software_trigger_enable(ADC_REGULAR_CHANNEL); // 启动转换 } // ADC中断服务函数 void ADC_IRQHandler(void) { if (adc_interrupt_flag_get(ADC_INT_FLAG_EOC)) { adc_interrupt_flag_clear(ADC_INT_FLAG_EOC); // 读取当前通道数据并存储 adc_values[adc_index] = adc_regular_data_read(); // 更新索引,循环处理 adc_index = (adc_index + 1) % ADC_CHANNEL_NUM; } } // 主函数 int main(void) { ADC_Config(); while (1) { // 主循环可处理adc_values中的数据 } } ``` #### 3. 关键点说明 1. **扫描模式**:通过`adc_channel_length_config`设置规则组通道数,实现多通道自动扫描。 2. **中断触发**:每个通道转换完成后触发`EOC`中断,通过索引管理数据存储位置。 3. **连续转换**:配置`ADC_CONTINUOUS_MODE`使能,实现自动循环采样。 4. **校准**:必须执行`adc_calibration_enable()`以保证采样精度[^1]。 #### 4. 性能优化建议 - 若采样频率较高,建议使用DMA传输以减少CPU中断负载(参考GD32L235的DMA配置方法)[^2][^3]。 - 调整`ADC_SAMPLETIME_55POINT5`参数以平衡速度和精度。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值