adc.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. /*
  2. * ADC采集模块 - v2.3 (10次平均版本)
  3. *
  4. * 功能:使用HAL库直接采集ADC通道数据,连续10次读取求平均值
  5. * - NTC温度(PA5-ADC1_IN5)-> 查表转换为温度存入 dev_info.ambient_temp
  6. * - 光控(PA4-ADC1_IN4)
  7. * - 电池电压(PA7-ADC1_IN7)-> 存入 sys_info.battery_voltage
  8. * - 太阳能充电电压(PA6-ADC1_IN6)-> 存入 sys_info.charge_voltage
  9. * - 灯管电流(PB0-ADC1_IN8)
  10. * - 高压输出电流(PB1-ADC1_IN9)
  11. *
  12. * Version: 2.3.0
  13. */
  14. /*********************↓ include ↓************************/
  15. #define DBG_TAG "ADC"
  16. #define DBG_LVL DBG_INFO
  17. #include <rtdbg.h>
  18. #include <rtthread.h>
  19. #include <board.h>
  20. #include "stm32f4xx_hal.h"
  21. #include "ym310_protecl.h"
  22. /*********************↑ include ↑************************/
  23. /*********************↓ define ↓************************/
  24. /* ADC通道配置 */
  25. #define ADC_CH_NTC 5 /* PA5 - ADC1_IN5 */
  26. #define ADC_CH_LIGHT 4 /* PA4 - ADC1_IN4 */
  27. #define ADC_CH_BAT 7 /* PA7 - ADC1_IN7 */
  28. #define ADC_CH_PV 6 /* PA6 - ADC1_IN6 */
  29. #define ADC_CH_LED 8 /* PB0 - ADC1_IN8 */
  30. #define ADC_CH_ELE 9 /* PB1 - ADC1_IN9 */
  31. /* 采集周期(毫秒) */
  32. #define ADC_CYCLE_NTC 1000
  33. #define ADC_CYCLE_LIGHT 100
  34. #define ADC_CYCLE_BAT 500
  35. #define ADC_CYCLE_PV 500
  36. #define ADC_CYCLE_LED 500
  37. #define ADC_CYCLE_ELE 5
  38. #define ADC_BASE_CYCLE_MS 5
  39. /* 采样次数(求平均值) */
  40. #define ADC_SAMPLE_COUNT 5
  41. /* 电压转换系数:ADC值 * 3.3 / 4095 * 2 * 1000 = ADC值 * 1.611 */
  42. #define ADC_TO_MV(x) ((x) * 1611 * 11 / 2 / 1000)
  43. //#define ADC_TO_MV(x) ((x) * 1611 / 1000)
  44. #define ADC_TO_MV_BAT(x) ((x) * 1611 * 11 / 2 / 1000)
  45. /* NTC温度查表:-30℃到100℃,共131个点 */
  46. /* 索引0对应-30℃,索引130对应100℃ */
  47. static const uint16_t tempRes_buf[131] = {
  48. 3889, 3876, 3862, 3848, 3833, 3817, 3801, 3784, 3766, 3747, /* -30 ~ -21 */
  49. 3727, 3707, 3686, 3663, 3640, 3616, 3592, 3566, 3539, 3511, /* -20 ~ -11 */
  50. 3483, 3453, 3423, 3392, 3359, 3326, 3292, 3257, 3221, 3185, /* -10 ~ -1 */
  51. 3147, /* 0 */
  52. 3109, 3070, 3030, 2990, 2948, 2906, 2864, 2821, 2777, 2733, /* 1 ~ 10 */
  53. 2689, 2644, 2599, 2553, 2508, 2462, 2416, 2369, 2324, 2277, /* 11 ~ 20 */
  54. 2231, 2185, 2139, 2093, 2048, 2003, 1958, 1914, 1870, 1825, /* 21 ~ 30 */
  55. 1783, 1739, 1698, 1656, 1615, 1575, 1534, 1495, 1457, 1419, /* 31 ~ 40 */
  56. 1382, 1345, 1310, 1275, 1242, 1207, 1174, 1143, 1111, 1080, /* 41 ~ 50 */
  57. 1051, 1021, 993, 965, 938, 911, 886, 861, 835, 811, /* 51 ~ 60 */
  58. 790, 766, 744, 725, 702, 683, 663, 645, 625, 607, /* 61 ~ 70 */
  59. 589, 574, 556, 540, 525, 512, 497, 481, 468, 455, /* 71 ~ 80 */
  60. 442, 429, 419, 406, 396, 382, 372, 362, 352, 342, /* 81 ~ 90 */
  61. 335, 324, 314, 307, 300, 289, 282, 275, 268, 261 /* 91 ~ 100 */
  62. };
  63. /*********************↑ define ↑************************/
  64. extern SYS_STATUS sys_sta;
  65. /*********************↓ 静态变量 ↓************************/
  66. static ADC_HandleTypeDef s_adc_handle;
  67. static rt_thread_t s_adc_thread = RT_NULL;
  68. static rt_bool_t s_adc_running = RT_FALSE;
  69. /* 各通道上次采集时间 */
  70. static rt_tick_t s_last_ntc = 0;
  71. static rt_tick_t s_last_light = 0;
  72. static rt_tick_t s_last_bat = 0;
  73. static rt_tick_t s_last_pv = 0;
  74. static rt_tick_t s_last_led = 0;
  75. static rt_tick_t s_last_ele = 0;
  76. /*********************↑ 静态变量 ↑************************/
  77. /*********************↓ 函数实现 ↓************************/
  78. /**
  79. * @brief 判断是否到达采样时间
  80. */
  81. static rt_bool_t is_time_to_sample(rt_tick_t *last_tick, rt_uint32_t cycle_ms)
  82. {
  83. rt_tick_t now = rt_tick_get();
  84. rt_tick_t cycle_tick = rt_tick_from_millisecond(cycle_ms);
  85. if ((now - *last_tick) >= cycle_tick)
  86. {
  87. *last_tick = now;
  88. return RT_TRUE;
  89. }
  90. return RT_FALSE;
  91. }
  92. /**
  93. * @brief 配置ADC引脚为模拟输入模式
  94. */
  95. static void adc_pin_init(void)
  96. {
  97. GPIO_InitTypeDef GPIO_InitStruct = {0};
  98. /* 使能GPIOA和GPIOB时钟 */
  99. __HAL_RCC_GPIOA_CLK_ENABLE();
  100. __HAL_RCC_GPIOB_CLK_ENABLE();
  101. /* 配置PA4, PA5, PA6, PA7为模拟输入 */
  102. GPIO_InitStruct.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
  103. GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  104. GPIO_InitStruct.Pull = GPIO_NOPULL;
  105. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  106. /* 配置PB0, PB1为模拟输入 */
  107. GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
  108. HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  109. //LOG_I("ADC pins configured as analog input");
  110. }
  111. /**
  112. * @brief 初始化ADC
  113. */
  114. static void adc_hw_init(void)
  115. {
  116. /* 使能ADC1时钟 */
  117. __HAL_RCC_ADC1_CLK_ENABLE();
  118. /* 配置ADC */
  119. s_adc_handle.Instance = ADC1;
  120. s_adc_handle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  121. s_adc_handle.Init.Resolution = ADC_RESOLUTION_12B;
  122. s_adc_handle.Init.ScanConvMode = DISABLE;
  123. s_adc_handle.Init.ContinuousConvMode = DISABLE;
  124. s_adc_handle.Init.DiscontinuousConvMode = DISABLE;
  125. s_adc_handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  126. s_adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  127. s_adc_handle.Init.NbrOfConversion = 1;
  128. s_adc_handle.Init.DMAContinuousRequests = DISABLE;
  129. s_adc_handle.Init.EOCSelection = ADC_EOC_SEQ_CONV;
  130. if (HAL_ADC_Init(&s_adc_handle) != HAL_OK)
  131. {
  132. LOG_E("ADC HAL init failed");
  133. return;
  134. }
  135. //LOG_I("ADC HAL initialized");
  136. }
  137. /**
  138. * @brief 读取单个ADC通道(单次读取)
  139. * @param channel ADC通道号 (ADC_CHANNEL_x)
  140. * @return ADC值(0-4095)
  141. */
  142. static uint32_t adc_read_single(uint32_t channel)
  143. {
  144. uint32_t value = 0;
  145. ADC_ChannelConfTypeDef sConfig = {0};
  146. /* 配置通道 */
  147. sConfig.Channel = channel;
  148. sConfig.Rank = 1;
  149. sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
  150. sConfig.Offset = 0;
  151. if (HAL_ADC_ConfigChannel(&s_adc_handle, &sConfig) != HAL_OK)
  152. {
  153. LOG_E("ADC config channel %d failed", channel);
  154. return 0;
  155. }
  156. /* 启动ADC转换 */
  157. HAL_ADC_Start(&s_adc_handle);
  158. /* 等待转换完成(超时100ms) */
  159. if (HAL_ADC_PollForConversion(&s_adc_handle, 100) == HAL_OK)
  160. {
  161. value = HAL_ADC_GetValue(&s_adc_handle);
  162. }
  163. else
  164. {
  165. LOG_E("ADC conversion timeout, channel=%d", channel);
  166. }
  167. /* 停止ADC */
  168. HAL_ADC_Stop(&s_adc_handle);
  169. return value;
  170. }
  171. /**
  172. * @brief 读取ADC通道(连续读取多次求平均值)
  173. * @param channel ADC通道号 (ADC_CHANNEL_x)
  174. * @return 平均ADC值(0-4095)
  175. */
  176. static uint32_t adc_read_average(uint32_t channel)
  177. {
  178. uint32_t sum = 0;
  179. uint32_t value;
  180. uint8_t i;
  181. for (i = 0; i < ADC_SAMPLE_COUNT; i++)
  182. {
  183. value = adc_read_single(channel);
  184. sum += value;
  185. /* 采样间隔5ms,让ADC稳定 */
  186. if (i < ADC_SAMPLE_COUNT - 1)
  187. {
  188. rt_thread_mdelay(5);
  189. }
  190. }
  191. return sum / ADC_SAMPLE_COUNT;
  192. }
  193. /**
  194. * @brief ADC值查表转换为温度(整数温度)
  195. * @param adc_value ADC采样值(0-4095)
  196. * @return 温度值(整数℃),超出范围返回边界值
  197. */
  198. static int8_t adc_to_temperature(uint32_t adc_value)
  199. {
  200. uint8_t i;
  201. /* 超出量程上限(低于-30℃) */
  202. if (adc_value >= tempRes_buf[0])
  203. {
  204. return -30;
  205. }
  206. /* 超出量程下限(高于100℃) */
  207. if (adc_value <= tempRes_buf[130])
  208. {
  209. return 100;
  210. }
  211. /* 线性查表 */
  212. for (i = 0; i < 130; i++)
  213. {
  214. if (adc_value >= tempRes_buf[i + 1] && adc_value <= tempRes_buf[i])
  215. {
  216. /* 线性插值,返回整数温度 */
  217. int32_t temp = -30 + i;
  218. uint32_t diff = tempRes_buf[i] - tempRes_buf[i + 1];
  219. if (diff > 0)
  220. {
  221. temp += (tempRes_buf[i] - adc_value) * 1 / diff;
  222. }
  223. return (int8_t)temp;
  224. }
  225. }
  226. return 100;
  227. }
  228. /**
  229. * @brief 执行一次ADC采集
  230. */
  231. static void adc_collect(void)
  232. {
  233. uint32_t value;
  234. int8_t temp;
  235. /* 1. NTC温度(PA5)- 查表转换为温度存入 dev_info.ambient_temp */
  236. if (is_time_to_sample(&s_last_ntc, ADC_CYCLE_NTC))
  237. {
  238. value = adc_read_average(ADC_CH_NTC);
  239. temp = adc_to_temperature(value);
  240. sensor.temp_ntc = temp * 10; /* 转换为0.1℃精度存储 */
  241. sensor.valid_ntc = VALID;
  242. //sys_sta.board_temp = temp * 10;
  243. LOG_D("NTC: avg=%d, temp=%d°C", value, temp);
  244. }
  245. /* 2. 光控(PA4)- 转换为百分比存入 sys_sta.light_percent */
  246. if (is_time_to_sample(&s_last_light, ADC_CYCLE_LIGHT))
  247. {
  248. value = adc_read_average(ADC_CH_LIGHT);
  249. /* ADC取值范围0-4095,计算百分比(保留一位小数,乘以10存储)*/
  250. /* 百分比 = (value / 4095) * 100 = value * 100 / 4095 */
  251. /* 保留一位小数:乘以10存储,即 (value * 1000 / 4095) */
  252. uint16_t percent_x10 = (uint16_t)(((uint32_t)value * 1000) / 4095);
  253. /* 限制范围0-1000(0.0%-100.0%)*/
  254. if (percent_x10 > 1000)
  255. percent_x10 = 1000;
  256. sys_sta.light_percent = percent_x10;
  257. LOG_D("LIGHT: avg=%d, percent=%d.%d%%",
  258. value, percent_x10 / 10, percent_x10 % 10);
  259. }
  260. /* 3. 电池电压(PA7)- 存入 sys_info.battery_voltage */
  261. if (is_time_to_sample(&s_last_bat, ADC_CYCLE_BAT))
  262. {
  263. value = adc_read_average(ADC_CH_BAT);
  264. sys_sta.battery_voltage = ADC_TO_MV_BAT(value);
  265. LOG_D("BAT: avg=%d, %dmV", value, sys_info.battery_voltage);
  266. }
  267. /* 4. 太阳能充电电压(PA6)- 存入 sys_info.charge_voltage */
  268. if (is_time_to_sample(&s_last_pv, ADC_CYCLE_PV))
  269. {
  270. value = adc_read_average(ADC_CH_PV);
  271. sys_sta.charge_voltage = ADC_TO_MV(value);
  272. LOG_D("PV: avg=%d, %dmV", value, sys_info.charge_voltage);
  273. }
  274. /* 5. 灯管电流(PB0)*/
  275. if (is_time_to_sample(&s_last_led, ADC_CYCLE_LED))
  276. {
  277. value = adc_read_average(ADC_CH_LED);
  278. //LOG_I("LED: avg=%d", value);
  279. sys_sta.lamp_current = value;
  280. }
  281. // static char times = 0;
  282. // times ++;
  283. /* 6. 高压输出电流(PB1)*/
  284. if (1)
  285. {
  286. value = adc_read_average(ADC_CH_ELE);
  287. // if(times >= 10)
  288. // {
  289. // LOG_I("ELE: avg=%d", value);
  290. // times = 0;
  291. // }
  292. sys_sta.hv_current = value;
  293. }
  294. }
  295. /**
  296. * @brief ADC采集线程入口
  297. */
  298. static void adc_thread_entry(void *parameter)
  299. {
  300. //LOG_I("ADC thread started (10 samples average)");
  301. // LOG_I(" NTC:%dms LIGHT:%dms BAT:%dms PV:%dms LED:%dms ELE:%dms",
  302. // ADC_CYCLE_NTC, ADC_CYCLE_LIGHT, ADC_CYCLE_BAT,
  303. // ADC_CYCLE_PV, ADC_CYCLE_LED, ADC_CYCLE_ELE);
  304. /* 初始化各通道上次采样时间 */
  305. rt_tick_t start_tick = rt_tick_get();
  306. s_last_ntc = start_tick;
  307. s_last_light = start_tick;
  308. s_last_bat = start_tick;
  309. s_last_pv = start_tick;
  310. s_last_led = start_tick;
  311. s_last_ele = start_tick;
  312. while (1)
  313. {
  314. adc_collect();
  315. rt_thread_mdelay(ADC_BASE_CYCLE_MS);
  316. }
  317. LOG_I("ADC thread stopped");
  318. }
  319. /**
  320. * @brief 启动ADC采集线程
  321. */
  322. static void adc_thread_start(void)
  323. {
  324. if (s_adc_thread != RT_NULL)
  325. {
  326. LOG_D("ADC thread already running");
  327. return;
  328. }
  329. /* 配置引脚 */
  330. adc_pin_init();
  331. /* 初始化ADC硬件 */
  332. adc_hw_init();
  333. /* 创建采集线程 */
  334. s_adc_running = RT_TRUE;
  335. s_adc_thread = rt_thread_create("adc_mon", adc_thread_entry, NULL,
  336. 1024, 20, 10);
  337. if (s_adc_thread == RT_NULL)
  338. {
  339. LOG_E("Failed to create ADC thread");
  340. s_adc_running = RT_FALSE;
  341. return;
  342. }
  343. rt_thread_startup(s_adc_thread);
  344. //LOG_I("ADC thread started");
  345. }
  346. /*********************↓ 自动初始化 ↓************************/
  347. static int adc_auto_init(void)
  348. {
  349. adc_thread_start();
  350. return 0;
  351. }
  352. INIT_APP_EXPORT(adc_auto_init);
  353. /*********************↑ 自动初始化 ↑************************/
  354. /*********************↓ MSH命令 ↓************************/
  355. static void cmd_adc_read(int argc, char **argv)
  356. {
  357. uint32_t val;
  358. int8_t temp;
  359. rt_kprintf("\n========== ADC VALUES (10 samples avg) ==========\n");
  360. val = adc_read_average(ADC_CH_NTC);
  361. temp = adc_to_temperature(val);
  362. rt_kprintf("NTC (PA5-ADC5): %d -> %d°C\n", val, temp);
  363. val = adc_read_average(ADC_CH_LIGHT);
  364. rt_kprintf("LIGHT (PA4-ADC4): %d %d.%d\n", val , sys_sta.light_percent /10 ,sys_sta.light_percent %10 );
  365. val = adc_read_average(ADC_CH_BAT);
  366. rt_kprintf("BAT (PA7-ADC7): %d (%d mV)\n", val, ADC_TO_MV_BAT(val));
  367. val = adc_read_average(ADC_CH_PV);
  368. rt_kprintf("PV (PA6-ADC6): %d (%d mV)\n", val, ADC_TO_MV(val));
  369. val = adc_read_average(ADC_CH_LED);
  370. rt_kprintf("LED (PB0-ADC8): %d\n", val);
  371. val = adc_read_average(ADC_CH_ELE);
  372. rt_kprintf("ELE (PB1-ADC9): %d\n", val);
  373. rt_kprintf("==================================================\n");
  374. rt_kprintf("sys_sta.battery_voltage = %d mV\n", sys_sta.battery_voltage);
  375. rt_kprintf("sys_sta.charge_voltage = %d mV\n", sys_sta.charge_voltage);
  376. rt_kprintf("sys_sta.ambient_temp = %d.%d°C\n",
  377. sensor.temp_ntc / 10, sensor.temp_ntc % 10);
  378. }
  379. MSH_CMD_EXPORT(cmd_adc_read, Read all ADC channels with 10 samples average);
  380. /*********************↑ MSH命令 ↑************************/