123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- #include "lcd/lcd.h"
- #include "fatfs/tf_card.h"
- #include <string.h>
- #define HZ2MS(X) ((uint64_t)((X * 53000.0)/(SystemCoreClock)))
- #define SOIL_THRESHOLD 40 /* Percent of soil humidity to trigger watering */
- #define DRY_INTERVAL (30 * 60 * 1000ULL) // 30min
- #define WET_INTERVAL (120 * 60 * 1000ULL) // 2h
- #define WATERING_INTERVAL (30 * 1000ULL) // 30s
- #define MANUAL_THRESHOLD (4 * 1000ULL) // 4s
- static int watering = 0;
- void init_uart0(void)
- {
- /* enable GPIO clock */
- rcu_periph_clock_enable(RCU_GPIOA);
- /* enable USART clock */
- rcu_periph_clock_enable(RCU_USART0);
- /* connect port to USARTx_Tx */
- gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
- /* connect port to USARTx_Rx */
- gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
- /* USART configure */
- usart_deinit(USART0);
- usart_baudrate_set(USART0, 115200U);
- usart_word_length_set(USART0, USART_WL_8BIT);
- usart_stop_bit_set(USART0, USART_STB_1BIT);
- usart_parity_config(USART0, USART_PM_NONE);
- usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
- usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);
- usart_receive_config(USART0, USART_RECEIVE_ENABLE);
- usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
- usart_enable(USART0);
- usart_interrupt_enable(USART0, USART_INT_RBNE);
- }
- void init_adc_inputs(void)
- {
- /* Pin config */
- rcu_periph_clock_enable(RCU_GPIOA);
- gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2);
- /* ADC config */
- rcu_periph_clock_enable(RCU_ADC0);
- rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8);
- adc_deinit(ADC0);
- adc_mode_config(ADC_MODE_FREE);
- adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);
- adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
- adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 3);
- adc_regular_channel_config(ADC0, 0, 0, ADC_SAMPLETIME_13POINT5);
- adc_regular_channel_config(ADC0, 1, 1, ADC_SAMPLETIME_13POINT5);
- adc_regular_channel_config(ADC0, 2, 2, ADC_SAMPLETIME_13POINT5);
- adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_NONE);
- adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);
- adc_enable(ADC0);
- adc_calibration_enable(ADC0);
- adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);
- (void)ADC_RDATA(ADC0);
- adc_deinit(ADC0);
- }
- uint16_t adc_read_input(int n)
- {
- uint16_t res;
- adc_mode_config(ADC_MODE_FREE);
- adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);
- adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
- adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 1);
- adc_regular_channel_config(ADC0, 0, n, ADC_SAMPLETIME_13POINT5);
- adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_NONE);
- adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);
- adc_enable(ADC0);
- delay_1ms(1);
- adc_calibration_enable(ADC0);
- adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);
- delay_1ms(1);
- res = ADC_RDATA(ADC0);
- adc_deinit(ADC0);
- return res;
- }
- static uint64_t watering_start = 0;
- static uint64_t dry_start = 0;
- static uint64_t wet_start = 0;
- static char banner[20] = "Happy plant!";
- static int banner_col = GREEN;
- void give_water(void)
- {
- uint64_t now = HZ2MS(get_timer_value());
- if (!watering) {
- watering_start = now;
- LEDR(1);
- watering = 1;
- snprintf(banner, 20, "Watering! ");
- banner_col = CYAN;
- } else if ((now - watering_start) > WATERING_INTERVAL) {
- watering_start = 0;
- LEDR(0);
- watering = 0;
- wet_start = now;
- dry_start = 0;
- snprintf(banner, 20, "Finished! ");
- banner_col = YELLOW;
- }
- }
- void thirsty(void)
- {
- volatile uint64_t now;
- int intvl;
- if (watering) {
- give_water();
- return;
- }
- now = HZ2MS(get_timer_value());
- if ((wet_start != 0) && ((now - wet_start) < WET_INTERVAL)) {
- intvl = (now - wet_start) / 1000;
- // snprintf(banner, 20, "H2O: %02d:%02d:%02d", intvl / 3600, (intvl % 3600) / 60, (intvl % 60));
- snprintf(banner, 20, "Last H2O: %02d:%02d ", intvl / 3600, (intvl % 3600) / 60);
- banner_col = GRAY;
- return;
- }
- if (dry_start == 0) {
- dry_start = now;
- return;
- }
- intvl = (now - dry_start) / 1000;
- // snprintf(banner, 20, "Thirsty: %02d:%02d:%02d", intvl / 3600, (intvl % 3600) / 60, (intvl % 60));
- snprintf(banner, 20, "Thirsty: %02d:%02d ", intvl / 3600, (intvl % 3600) / 60);
- banner_col = RED;
- if ((now - dry_start) > DRY_INTERVAL) {
- dry_start = 0;
- give_water();
- }
- }
- #define PCT_UNSET 0xFFFFFFFF
- int main(void)
- {
- uint8_t mount_is_ok = 1; /* 0: mount successful ; 1: mount failed */
- int offset = 0;
- char rstr0[24];
- char rstr1[24];
- char rstr2[24];
- char rstr3[24];
- uint32_t ctr = 0;
- uint16_t raw_temp, raw_soil, raw_light;
- uint32_t temp_integer, temp_fractions;
- uint32_t soil_sense, light_sense, soil_pct = PCT_UNSET, light_pct = PCT_UNSET;
- int half_degree = 0;
- int col_water, col_temp, col_light;
- uint64_t button_press_start = 0;
- /* Init GPIOs */
- rcu_periph_clock_enable(RCU_GPIOA);
- rcu_periph_clock_enable(RCU_GPIOC);
- /* Water pump + Red Led */
- gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
- LEDR(0);
- /* User Button */
- gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_2MHZ, GPIO_PIN_8);
- /* HW init: uart, ADC, Display */
- init_uart0();
- init_adc_inputs();
- Lcd_Init();
- /* Display background */
- LCD_Clear(BLACK);
- BACK_COLOR=BLACK;
- /* Clear screen */
- LCD_Clear(BLACK);
- while (1)
- {
- delay_1ms(20);
- /* Read ADCs */
- raw_temp = adc_read_input(0);
- raw_soil = adc_read_input(1);
- raw_light = adc_read_input(2);
- temp_integer = (raw_temp * 330);
- temp_fractions = temp_integer % 4096;
- temp_integer >>= 12;
- if (temp_fractions > 1024 && temp_fractions < 3072)
- half_degree = 1;
- else
- half_degree = 0;
- if (temp_fractions >= 3072)
- temp_integer++;
- /* sense in 1/16s */
- soil_sense = (raw_soil * 100) / 4096;
- light_sense = (raw_light * 100) / 4096;
- if (soil_pct == PCT_UNSET)
- soil_pct = soil_sense;
- else
- soil_pct = (15 * soil_pct + soil_sense) / 16; /* 15/16 old + 1/16 sense */
-
- if (light_pct == PCT_UNSET)
- light_pct = light_sense;
- else
- light_pct = (15 * light_pct + light_sense) / 16; /* 15/16 old + 1/16 sense */
- if (soil_pct < SOIL_THRESHOLD) {
- col_water = RED;
- } else {
- snprintf(banner, 20, " Happy plant! ");
- banner_col = GREEN;
- col_water = GREEN;
- dry_start = 0;
- }
- if (!watering && (soil_pct < SOIL_THRESHOLD)) {
- thirsty();
- } else if (watering)
- give_water();
- if (temp_integer < 10)
- col_temp = CYAN;
- else if (temp_integer > 30)
- col_temp = RED;
- else
- col_temp = GREEN;
- if (light_pct < 30)
- col_light = BLUE;
- else
- col_light = YELLOW;
- memset(rstr0, 0, 20);
- memset(rstr1, 0, 20);
- memset(rstr2, 0, 20);
- snprintf(rstr0, 20, "Temp : %u.%c ", temp_integer, half_degree?'5':'0');
- snprintf(rstr1, 20, "Soil hum: %d %% ", soil_pct);
- snprintf(rstr2, 20, "Light : %d %% ", light_pct);
- LCD_ShowString (12, 16, (u8 *)banner, banner_col);
- LCD_ShowString(12, 32, (u8 *)(rstr0), col_temp);
- LCD_ShowString(12, 48, (u8 *)(rstr1), col_water);
- LCD_ShowString(12, 64, (u8 *)(rstr2), col_light);
- if (!watering && gpio_input_bit_get(GPIOA, GPIO_PIN_8)) {
- uint64_t now = HZ2MS(get_timer_value());
- if (button_press_start == 0) {
- button_press_start = now;
- } else {
- if ((now - button_press_start) > MANUAL_THRESHOLD)
- give_water();
- }
- } else {
- button_press_start = 0;
- }
- }
- }
- int _put_char(int ch)
- {
- usart_data_transmit(USART0, (uint8_t) ch );
- while ( usart_flag_get(USART0, USART_FLAG_TBE)== RESET){
- }
- return ch;
- }
|