main.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. #include "lcd/lcd.h"
  2. #include "fatfs/tf_card.h"
  3. #include <string.h>
  4. #define HZ2MS(X) ((uint64_t)((X * 53000.0)/(SystemCoreClock)))
  5. #define SOIL_THRESHOLD 40 /* Percent of soil humidity to trigger watering */
  6. #define DRY_INTERVAL (30 * 60 * 1000ULL) // 30min
  7. #define WET_INTERVAL (120 * 60 * 1000ULL) // 2h
  8. #define WATERING_INTERVAL (30 * 1000ULL) // 30s
  9. #define MANUAL_THRESHOLD (4 * 1000ULL) // 4s
  10. static int watering = 0;
  11. void init_uart0(void)
  12. {
  13. /* enable GPIO clock */
  14. rcu_periph_clock_enable(RCU_GPIOA);
  15. /* enable USART clock */
  16. rcu_periph_clock_enable(RCU_USART0);
  17. /* connect port to USARTx_Tx */
  18. gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
  19. /* connect port to USARTx_Rx */
  20. gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
  21. /* USART configure */
  22. usart_deinit(USART0);
  23. usart_baudrate_set(USART0, 115200U);
  24. usart_word_length_set(USART0, USART_WL_8BIT);
  25. usart_stop_bit_set(USART0, USART_STB_1BIT);
  26. usart_parity_config(USART0, USART_PM_NONE);
  27. usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
  28. usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);
  29. usart_receive_config(USART0, USART_RECEIVE_ENABLE);
  30. usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
  31. usart_enable(USART0);
  32. usart_interrupt_enable(USART0, USART_INT_RBNE);
  33. }
  34. void init_adc_inputs(void)
  35. {
  36. /* Pin config */
  37. rcu_periph_clock_enable(RCU_GPIOA);
  38. gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2);
  39. /* ADC config */
  40. rcu_periph_clock_enable(RCU_ADC0);
  41. rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8);
  42. adc_deinit(ADC0);
  43. adc_mode_config(ADC_MODE_FREE);
  44. adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);
  45. adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
  46. adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 3);
  47. adc_regular_channel_config(ADC0, 0, 0, ADC_SAMPLETIME_13POINT5);
  48. adc_regular_channel_config(ADC0, 1, 1, ADC_SAMPLETIME_13POINT5);
  49. adc_regular_channel_config(ADC0, 2, 2, ADC_SAMPLETIME_13POINT5);
  50. adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_NONE);
  51. adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);
  52. adc_enable(ADC0);
  53. adc_calibration_enable(ADC0);
  54. adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);
  55. (void)ADC_RDATA(ADC0);
  56. adc_deinit(ADC0);
  57. }
  58. uint16_t adc_read_input(int n)
  59. {
  60. uint16_t res;
  61. adc_mode_config(ADC_MODE_FREE);
  62. adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);
  63. adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
  64. adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 1);
  65. adc_regular_channel_config(ADC0, 0, n, ADC_SAMPLETIME_13POINT5);
  66. adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_NONE);
  67. adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);
  68. adc_enable(ADC0);
  69. delay_1ms(1);
  70. adc_calibration_enable(ADC0);
  71. adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);
  72. delay_1ms(1);
  73. res = ADC_RDATA(ADC0);
  74. adc_deinit(ADC0);
  75. return res;
  76. }
  77. static uint64_t watering_start = 0;
  78. static uint64_t dry_start = 0;
  79. static uint64_t wet_start = 0;
  80. static char banner[20] = "Happy plant!";
  81. static int banner_col = GREEN;
  82. void give_water(void)
  83. {
  84. uint64_t now = HZ2MS(get_timer_value());
  85. if (!watering) {
  86. watering_start = now;
  87. LEDR(1);
  88. watering = 1;
  89. snprintf(banner, 20, "Watering! ");
  90. banner_col = CYAN;
  91. } else if ((now - watering_start) > WATERING_INTERVAL) {
  92. watering_start = 0;
  93. LEDR(0);
  94. watering = 0;
  95. wet_start = now;
  96. dry_start = 0;
  97. snprintf(banner, 20, "Finished! ");
  98. banner_col = YELLOW;
  99. }
  100. }
  101. void thirsty(void)
  102. {
  103. volatile uint64_t now;
  104. int intvl;
  105. if (watering) {
  106. give_water();
  107. return;
  108. }
  109. now = HZ2MS(get_timer_value());
  110. if ((wet_start != 0) && ((now - wet_start) < WET_INTERVAL)) {
  111. intvl = (now - wet_start) / 1000;
  112. // snprintf(banner, 20, "H2O: %02d:%02d:%02d", intvl / 3600, (intvl % 3600) / 60, (intvl % 60));
  113. snprintf(banner, 20, "Last H2O: %02d:%02d ", intvl / 3600, (intvl % 3600) / 60);
  114. banner_col = GRAY;
  115. return;
  116. }
  117. if (dry_start == 0) {
  118. dry_start = now;
  119. return;
  120. }
  121. intvl = (now - dry_start) / 1000;
  122. // snprintf(banner, 20, "Thirsty: %02d:%02d:%02d", intvl / 3600, (intvl % 3600) / 60, (intvl % 60));
  123. snprintf(banner, 20, "Thirsty: %02d:%02d ", intvl / 3600, (intvl % 3600) / 60);
  124. banner_col = RED;
  125. if ((now - dry_start) > DRY_INTERVAL) {
  126. dry_start = 0;
  127. give_water();
  128. }
  129. }
  130. #define PCT_UNSET 0xFFFFFFFF
  131. int main(void)
  132. {
  133. uint8_t mount_is_ok = 1; /* 0: mount successful ; 1: mount failed */
  134. int offset = 0;
  135. char rstr0[24];
  136. char rstr1[24];
  137. char rstr2[24];
  138. char rstr3[24];
  139. uint32_t ctr = 0;
  140. uint16_t raw_temp, raw_soil, raw_light;
  141. uint32_t temp_integer, temp_fractions;
  142. uint32_t soil_sense, light_sense, soil_pct = PCT_UNSET, light_pct = PCT_UNSET;
  143. int half_degree = 0;
  144. int col_water, col_temp, col_light;
  145. uint64_t button_press_start = 0;
  146. /* Init GPIOs */
  147. rcu_periph_clock_enable(RCU_GPIOA);
  148. rcu_periph_clock_enable(RCU_GPIOC);
  149. /* Water pump + Red Led */
  150. gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
  151. LEDR(0);
  152. /* User Button */
  153. gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_2MHZ, GPIO_PIN_8);
  154. /* HW init: uart, ADC, Display */
  155. init_uart0();
  156. init_adc_inputs();
  157. Lcd_Init();
  158. /* Display background */
  159. LCD_Clear(BLACK);
  160. BACK_COLOR=BLACK;
  161. /* Clear screen */
  162. LCD_Clear(BLACK);
  163. while (1)
  164. {
  165. delay_1ms(20);
  166. /* Read ADCs */
  167. raw_temp = adc_read_input(0);
  168. raw_soil = adc_read_input(1);
  169. raw_light = adc_read_input(2);
  170. temp_integer = (raw_temp * 330);
  171. temp_fractions = temp_integer % 4096;
  172. temp_integer >>= 12;
  173. if (temp_fractions > 1024 && temp_fractions < 3072)
  174. half_degree = 1;
  175. else
  176. half_degree = 0;
  177. if (temp_fractions >= 3072)
  178. temp_integer++;
  179. /* sense in 1/16s */
  180. soil_sense = (raw_soil * 100) / 4096;
  181. light_sense = (raw_light * 100) / 4096;
  182. if (soil_pct == PCT_UNSET)
  183. soil_pct = soil_sense;
  184. else
  185. soil_pct = (15 * soil_pct + soil_sense) / 16; /* 15/16 old + 1/16 sense */
  186. if (light_pct == PCT_UNSET)
  187. light_pct = light_sense;
  188. else
  189. light_pct = (15 * light_pct + light_sense) / 16; /* 15/16 old + 1/16 sense */
  190. if (soil_pct < SOIL_THRESHOLD) {
  191. col_water = RED;
  192. } else {
  193. snprintf(banner, 20, " Happy plant! ");
  194. banner_col = GREEN;
  195. col_water = GREEN;
  196. dry_start = 0;
  197. }
  198. if (!watering && (soil_pct < SOIL_THRESHOLD)) {
  199. thirsty();
  200. } else if (watering)
  201. give_water();
  202. if (temp_integer < 10)
  203. col_temp = CYAN;
  204. else if (temp_integer > 30)
  205. col_temp = RED;
  206. else
  207. col_temp = GREEN;
  208. if (light_pct < 30)
  209. col_light = BLUE;
  210. else
  211. col_light = YELLOW;
  212. memset(rstr0, 0, 20);
  213. memset(rstr1, 0, 20);
  214. memset(rstr2, 0, 20);
  215. snprintf(rstr0, 20, "Temp : %u.%c ", temp_integer, half_degree?'5':'0');
  216. snprintf(rstr1, 20, "Soil hum: %d %% ", soil_pct);
  217. snprintf(rstr2, 20, "Light : %d %% ", light_pct);
  218. LCD_ShowString (12, 16, (u8 *)banner, banner_col);
  219. LCD_ShowString(12, 32, (u8 *)(rstr0), col_temp);
  220. LCD_ShowString(12, 48, (u8 *)(rstr1), col_water);
  221. LCD_ShowString(12, 64, (u8 *)(rstr2), col_light);
  222. if (!watering && gpio_input_bit_get(GPIOA, GPIO_PIN_8)) {
  223. uint64_t now = HZ2MS(get_timer_value());
  224. if (button_press_start == 0) {
  225. button_press_start = now;
  226. } else {
  227. if ((now - button_press_start) > MANUAL_THRESHOLD)
  228. give_water();
  229. }
  230. } else {
  231. button_press_start = 0;
  232. }
  233. }
  234. }
  235. int _put_char(int ch)
  236. {
  237. usart_data_transmit(USART0, (uint8_t) ch );
  238. while ( usart_flag_get(USART0, USART_FLAG_TBE)== RESET){
  239. }
  240. return ch;
  241. }