ADC.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /*********************************************************************************************************
  2. * 模块名称:ADC.c
  3. * 摘 要:内部ADC应用,采用12bit。
  4. * 当前版本:1.0.0
  5. * 作 者:anycrying
  6. * 完成日期:2024年04月06日
  7. * 内 容:
  8. * 注 意:
  9. **********************************************************************************************************
  10. * 取代版本:
  11. * 作 者:
  12. * 完成日期:
  13. * 修改内容:
  14. * 修改文件:
  15. *********************************************************************************************************/
  16. /*********************************************************************************************************
  17. * 包含头文件
  18. *********************************************************************************************************/
  19. #include <stdbool.h>
  20. #include "ADC.h"
  21. #include "gd32e230x_conf.h"
  22. #include "SysTick.h"
  23. #include "Timer.h"
  24. #include "math.h"
  25. /*********************************************************************************************************
  26. * 宏定义
  27. *********************************************************************************************************/
  28. /*********************************************************************************************************
  29. * 枚举结构体
  30. *********************************************************************************************************/
  31. /*********************************************************************************************************
  32. * 内部变量定义
  33. *********************************************************************************************************/
  34. bool adc_data_ok_flag = false;
  35. uint8_t adc_sample_n;//采样次数
  36. uint16_t adc_original_value[ADC_CH_N+ADC_V_CHN]={0};//存放各通道原始值
  37. uint16_t adc_calc_value[ADC_Avg_N][ADC_CH_N+ADC_V_CHN];//各通道中间过程计算值
  38. uint32_t adc_Avg_value[ADC_CH_N+ADC_V_CHN];//存放各通道平均值
  39. extern uint16_t adc_data_zero[ADC_CH_N+ADC_V_CHN];
  40. /*********************************************************************************************************
  41. * 内部函数声明
  42. *********************************************************************************************************/
  43. /*********************************************************************************************************
  44. * 函数名称:Init_ADC
  45. * 函数功能:初始化ADC模块
  46. * 输入参数:void
  47. * 输出参数:void
  48. * 返 回 值:void
  49. * 创建日期:2024年04月06日
  50. * 注 意:
  51. *********************************************************************************************************/
  52. void Init_ADC(void)
  53. {
  54. adc_sample_n = 0;
  55. ConfigADCGPIO();
  56. }
  57. /*********************************************************************************************************
  58. * 函数名称:ConfigADCGPIO
  59. * 函数功能:配置ADC的GPIO ,ADC通道3和4用于串口通信,所以扩展用了ADC通道9和10
  60. * 输入参数:void
  61. * 输出参数:void
  62. * 返 回 值:void
  63. * 创建日期:2024年04月06日
  64. * 注 意:
  65. *********************************************************************************************************/
  66. void ConfigADCGPIO(void)
  67. {
  68. //使能RCU相关时钟
  69. rcu_periph_clock_enable(ADC_0_5_RCU);//使能GPIOA的时钟
  70. rcu_periph_clock_enable(ADC_67_RCU);//使能GPIOB的时钟
  71. //使能ADC时钟
  72. rcu_periph_clock_enable(RCU_ADC);
  73. //使能DMA的时钟
  74. rcu_periph_clock_enable(RCU_DMA);
  75. //配置ADC时钟
  76. rcu_adc_clock_config(RCU_ADCCK_APB2_DIV6);
  77. //设置GPIO为ADC接口
  78. #if NO_USE_IM1253E
  79. gpio_mode_set(ADC_0_5_IO, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, ADC_ch0|ADC_ch1|ADC_ch2|ADC_ch3|ADC_ch4|ADC_ch5|ADC_Vol_ch1|ADC_Vol_ch2);
  80. #else
  81. gpio_mode_set(ADC_0_5_IO, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, ADC_ch0|ADC_ch1|ADC_ch2|ADC_ch3|ADC_ch4|ADC_ch5);//ADC通道3和4用于串口通信,所以扩展用了ADC通道9和10
  82. #endif
  83. gpio_mode_set(ADC_67_IO, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, ADC_ch6|ADC_ch7);
  84. //复位ADC外设
  85. adc_deinit();
  86. //配置DMA
  87. ADC_dma_config();
  88. //内部ADC配置
  89. adc_special_function_config(ADC_SCAN_MODE,ENABLE);//配置ADC扫描转换模式
  90. adc_special_function_config(ADC_CONTINUOUS_MODE,ENABLE);//配置ADC连续转换模式
  91. adc_external_trigger_source_config(ADC_REGULAR_CHANNEL,ADC_EXTTRIG_REGULAR_NONE);//配置ADC外部触发是软件触发
  92. adc_data_alignment_config(ADC_DATAALIGN_RIGHT);//配置ADC数据对齐方式是右对齐
  93. adc_resolution_config(ADC_RESOLUTION_12B);//配置ADC为12位
  94. #if NO_USE_IM1253E
  95. adc_channel_length_config(ADC_REGULAR_CHANNEL, ADC_CH_N+ADC_V_CHN);
  96. adc_regular_channel_config(8U, ADC_CHANNEL_3, ADC_SAMPLETIME_55POINT5);
  97. adc_regular_channel_config(9U, ADC_CHANNEL_2, ADC_SAMPLETIME_55POINT5);
  98. #else
  99. adc_channel_length_config(ADC_REGULAR_CHANNEL, ADC_CH_N);//配置ADC规则通道组成或注入通道组的长度,因为用到8个通道,所以是8
  100. #endif
  101. adc_regular_channel_config(0U, ADC_CHANNEL_0, ADC_SAMPLETIME_55POINT5);//配置ADC通道组
  102. adc_regular_channel_config(1U, ADC_CHANNEL_1, ADC_SAMPLETIME_55POINT5);
  103. adc_regular_channel_config(2U, ADC_CHANNEL_4, ADC_SAMPLETIME_55POINT5);
  104. adc_regular_channel_config(3U, ADC_CHANNEL_5, ADC_SAMPLETIME_55POINT5);
  105. adc_regular_channel_config(4U, ADC_CHANNEL_6, ADC_SAMPLETIME_55POINT5);
  106. adc_regular_channel_config(5U, ADC_CHANNEL_7, ADC_SAMPLETIME_55POINT5);
  107. adc_regular_channel_config(6U, ADC_CHANNEL_8, ADC_SAMPLETIME_55POINT5);
  108. adc_regular_channel_config(7U, ADC_CHANNEL_9, ADC_SAMPLETIME_55POINT5);
  109. adc_enable();//使能
  110. adc_enable();//使能
  111. //delay_ms(2);
  112. adc_calibration_enable();//校准复位
  113. adc_dma_mode_enable();//使能DMA
  114. adc_software_trigger_enable(ADC_REGULAR_CHANNEL);//软件触发
  115. adc_software_trigger_enable(ADC_REGULAR_CHANNEL);
  116. //dma_interrupt_enable(DMA_CH0,DMA_INT_FTF);
  117. }
  118. /*********************************************************************************************************
  119. * 函数名称:ADC_dma_config
  120. * 函数功能:配置ADC采用DMA方式
  121. * 输入参数:void
  122. * 输出参数:void
  123. * 返 回 值:void
  124. * 创建日期:2024年04月06日
  125. * 注 意:
  126. *********************************************************************************************************/
  127. void ADC_dma_config(void)
  128. {
  129. //通道参数配置
  130. dma_parameter_struct dma_data_parameter;
  131. //使能ADC时钟
  132. rcu_periph_clock_enable(RCU_ADC);
  133. //使能DMA的时钟
  134. rcu_periph_clock_enable(RCU_DMA);
  135. //复位DMA通道
  136. dma_deinit(DMA_CH0);
  137. //初始化DMA为单数据模式
  138. dma_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA);//设置DMA外设地址,也是DMA数据传输的源地址,ADC单次采样转换结束后,会将数据存入ADC_RDATA地址中
  139. dma_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;//设置DMA数据传输的源地址自增算法取消,ADC每次转换后数据存入地址不变
  140. dma_data_parameter.memory_addr = (uint32_t)(adc_original_value);//设置DMA存储器地址,也是DMA数据传输的目标地址
  141. dma_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;//设置DMA数据传输目标地址自增算法使能,因为DMA每个周期需要传送八个数据,所以在一个周期内,目标地址要自增
  142. dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;//设置DMA从外设中读出数据的位数,因为ADC转换后的数值是12位,用16位数值表示,所以这里设置为1字
  143. dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_16BIT; //设置DMA存入存储器的数据位数
  144. dma_data_parameter.direction = DMA_PERIPHERAL_TO_MEMORY;//设置DMA的数据传输方向
  145. #if NO_USE_IM1253E
  146. dma_data_parameter.number = ADC_CH_N + ADC_V_CHN;
  147. #else
  148. dma_data_parameter.number = ADC_CH_N;//设置DMA一个周期要传输的数据个数,用了8个通道的ADC,所以在一个周期内要传输8个数据
  149. #endif
  150. dma_data_parameter.priority = DMA_PRIORITY_HIGH;//设置DMA数据传输高优先级
  151. dma_circulation_enable(DMA_CH0);//DMA循环模式使能,这样DMA在传输8个数据后,存储地址复位,自动开启下一轮传输
  152. dma_init(DMA_CH0, &dma_data_parameter);//初始化DMA
  153. dma_memory_to_memory_disable(DMA_CH0);//这里用不上,所以存储器到存储器DMA传输取消
  154. dma_channel_enable(DMA_CH0);//使能DMA通道
  155. }
  156. /*********************************************************************************************************
  157. * 函数名称:DC_I_calfunction
  158. * 函数功能:直流电流计算公式函数
  159. * 输入参数:uint16_t 电流的ADC值
  160. * 输出参数:uint32_t 浮点电流值(mA)
  161. * 返 回 值:uint32_t 浮点电流值(mA)
  162. * 创建日期:2024年04月06日
  163. * 注 意:12位ADC转换公式:实际电压值V = (ADC参考电压Vref * 采样数值N) / 2^12
  164. * 电流传感器转换公式:实际电流值I(A) = 实际电压值V / 灵敏度参数(V/A)
  165. * 实际计算时,让小数变成整数,最终结果扩大1000倍
  166. *********************************************************************************************************/
  167. uint32_t DC_I_calfunction(uint16_t da)
  168. {
  169. uint32_t temp_i = 0;
  170. uint32_t temp_v = 0;
  171. if(da > 0)
  172. {
  173. temp_v = da;
  174. temp_v *= ADC_Vref;
  175. temp_v *= 1000;
  176. temp_v = temp_v >> 12;//temp_v /= ADC_Fulscale;
  177. temp_v /= A_gain;
  178. temp_i = temp_v / I_sens;
  179. temp_i /= 10;//去掉第3位小数
  180. temp_i *= 10;
  181. if(temp_i < 20)
  182. temp_i = 0;
  183. return temp_i;
  184. }
  185. else
  186. {
  187. return 0;
  188. }
  189. }
  190. #if NO_USE_IM1253E
  191. uint32_t DC_V_calfunction(uint16_t va)
  192. {
  193. uint32_t temp_i = 0;
  194. uint32_t temp_v = 0;
  195. if(va)
  196. {
  197. temp_v = va;
  198. temp_v *= ADC_Vref;
  199. temp_v *= 1000;
  200. temp_v = temp_v >> 12;
  201. temp_v *= ADC_V_Gain;
  202. temp_i = temp_v;
  203. temp_i /= 10;
  204. temp_i /= 10;
  205. return temp_i;
  206. }
  207. return 0;
  208. }
  209. //void read_voltage_val(void)
  210. //{
  211. // if(adc_sample_n < ADC_Avg_N)
  212. // {
  213. // adc_Avg_value[ADC_VOL] += adc_original_value[ADC_VOL];
  214. // adc_sample_n++;
  215. // }else
  216. // {
  217. // adc_sample_n = 0;
  218. // adc_Avg_value[ADC_VOL] = adc_Avg_value[ADC_VOL] / ADC_Avg_N;
  219. // if(adc_Avg_value[ADC_VOL] > adc_data_zero[ADC_VOL])
  220. // {
  221. // adc_Avg_value[ADC_VOL] -= adc_data_zero[ADC_VOL];
  222. // }
  223. // else
  224. // {
  225. // adc_Avg_value[ADC_VOL] = 0;
  226. // }
  227. // }
  228. //}
  229. #endif
  230. /*********************************************************************************************************
  231. * 函数名称:read_adc_val
  232. * 函数功能:读取ADC各通道的数据,并将原始值存储到缓冲区,采样ADC_Avg_N次后才计算均值
  233. * 输入参数:void
  234. * 输出参数:void
  235. * 返 回 值:void
  236. * 创建日期:2024年04月06日
  237. * 注 意:
  238. *********************************************************************************************************/
  239. static uint16_t sort_buff[ADC_CH_N+ADC_V_CHN][ADC_Avg_N] = {0};
  240. static void buff_sort(uint16_t *arr,int num)
  241. {
  242. int i,j;
  243. uint16_t tmp;
  244. for(j=0; j < num;j++)
  245. {
  246. for(i =0; i < (num -j-1);i++)
  247. {
  248. if(arr[i+1] > arr[i])
  249. {
  250. tmp = arr[i+1];
  251. arr[i+1] = arr[i];
  252. arr[i] = tmp;
  253. }
  254. }
  255. }
  256. }
  257. static uint32_t calculate_all(uint16_t *arr,int num)
  258. {
  259. uint32_t temp;
  260. for(int i= 0; i < num;i++)
  261. {
  262. temp+=arr[i];
  263. }
  264. temp = (temp /num);
  265. return temp;
  266. }
  267. void read_adc_val(void)
  268. {
  269. int8_t i = 0;
  270. if(adc_sample_n < ADC_Avg_N)
  271. {
  272. for(i = 0;i < ADC_CH_N ;i++)
  273. {
  274. sort_buff[i][adc_sample_n] = adc_original_value[i];
  275. //adc_Avg_value[i] += adc_original_value[i];
  276. }
  277. #if NO_USE_IM1253E
  278. sort_buff[ADC_VOL][adc_sample_n] = (uint16_t)(abs(adc_original_value[ADC_VOL] - adc_original_value[ADC_VOL+1]));
  279. //adc_Avg_value[ADC_VOL] += (uint16_t)(abs(adc_original_value[ADC_VOL] - adc_original_value[ADC_VOL+1]));
  280. #endif
  281. adc_sample_n++;
  282. }
  283. else
  284. {
  285. adc_sample_n = 0;
  286. for(i = 0;i < ADC_CH_N ;i++)
  287. {
  288. uint16_t *arr = &sort_buff[i][0];
  289. buff_sort(arr,ADC_Avg_N);
  290. //arr = &sort_buff[i][2];
  291. //adc_Avg_value[i] = calculate_all(arr,ADC_Avg_N);
  292. adc_Avg_value[i] = sort_buff[i][6];
  293. //adc_Avg_value[i] = adc_Avg_value[i] / ADC_Avg_N;
  294. if(adc_Avg_value[i] > adc_data_zero[i])
  295. {
  296. adc_Avg_value[i] -= adc_data_zero[i];
  297. }
  298. else
  299. {
  300. adc_Avg_value[i] = 0;
  301. }
  302. }
  303. #if NO_USE_IM1253E
  304. //adc_Avg_value[ADC_VOL] = adc_Avg_value[ADC_VOL] / ADC_Avg_N;
  305. uint16_t *arr = &sort_buff[ADC_VOL][0];
  306. buff_sort(arr,ADC_Avg_N);
  307. arr = &sort_buff[ADC_VOL][1];
  308. //adc_Avg_value[ADC_VOL] = calculate_all(arr,ADC_Avg_N-3);
  309. adc_Avg_value[ADC_VOL] = sort_buff[ADC_VOL][6];
  310. if(adc_Avg_value[ADC_VOL] > adc_data_zero[ADC_VOL])
  311. {
  312. adc_Avg_value[ADC_VOL] -= adc_data_zero[ADC_VOL];
  313. }
  314. else
  315. {
  316. adc_Avg_value[ADC_VOL] = 0;
  317. }
  318. #endif
  319. adc_data_ok_flag = true;
  320. }
  321. }
  322. #if NO_USE_IM1253E
  323. #endif