/* * File: project_main.c * Author: Nakul Talwar & Peter Phelan * * Created on September 18, 2017, 10:11 AM */ //#include //#include #include "config.h" #include "plib.h" #include "xc.h" #include "adc_intf.h" #include "tft_master.h" #include "tft_gfx.h" // need for rand function #include // threading library // config.h sets 40 MHz #define SYS_FREQ 40000000 #define PBLCK 40000000 #include "pt_cornell_1_2.h" //interrupt period setting //const int PR = SYS_FREQ/60 - 1; //string buffers char buffer[30], buffer1[30], buffer2[30], buffer3[30], buffer4[30]; #define BATTERY_PIN 9 #define LED1_PIN BIT_8 #define LED2_PIN BIT_9 #define LED3_PIN BIT_10 #define LED4_PIN BIT_5 #define BACKLIGHT_PIN BIT_0 // //#pragma config FSOSCEN = ON //declared protothread structures static struct pt pt_battery_status, pt_sleep, pt_timer; //store current battery level read from ADC int battery_level; int count; //debugging //store current time and date rtccTime current_time, prev_time; rtccDate current_date; rtccTime initial_time; rtccTime initial_date; long initial_time_num = 0x11000000; long initial_date_num = 0x17120805; //used for sped up version of system for testing purposes int night_mode_duration = 1; //duration of night mode (in minutes) int time_till_night_mode = 1; //time from start time to night mode begin (in minutes) // system 1 second interval tick int sys_time_seconds ; int pwm, pwm_prev; int pwm_period = 2250; int adc0, adc1, adc0_prev, adc1_prev, diff; int getBatteryLevel(){ return readADC(BATTERY_PIN); } //setup output compare for PWM void initOC(){ PR2 = 49999; OC1RS = 2500; OC1R = 2500; OC1CON = 0x800E; PPSOutput(1, RPB7, OC1); OpenTimer3(T3_ON | T3_PS_1_16, 49999); } void clearLEDs(){ mPORTBClearBits(LED1_PIN); mPORTBClearBits(LED2_PIN); mPORTBClearBits(LED3_PIN); mPORTBClearBits(LED4_PIN); } void updateLEDs(){ if(battery_level < 700){ clearLEDs(); } else if(battery_level < 760){ mPORTBToggleBits(LED1_PIN); mPORTBClearBits(LED2_PIN); mPORTBClearBits(LED3_PIN); mPORTBClearBits(LED4_PIN); } else if(battery_level < 800){ mPORTBSetBits(LED1_PIN); mPORTBToggleBits(LED2_PIN); mPORTBClearBits(LED3_PIN); mPORTBClearBits(LED4_PIN); } else if(battery_level < 850){ mPORTBSetBits(LED1_PIN); mPORTBSetBits(LED2_PIN); mPORTBToggleBits(LED3_PIN); mPORTBClearBits(LED4_PIN); } else if(battery_level < 900){ mPORTBSetBits(LED1_PIN); mPORTBSetBits(LED2_PIN); mPORTBSetBits(LED3_PIN); mPORTBToggleBits(LED4_PIN); } else{ mPORTBSetBits(LED1_PIN); mPORTBSetBits(LED2_PIN); mPORTBSetBits(LED3_PIN); mPORTBSetBits(LED4_PIN); } } // === Motor control and LCD display thread================================================= // read ADC values and update motor PWM period // update display for debugging static PT_THREAD (protothread_timer(struct pt *pt)) { PT_BEGIN(pt); tft_setCursor(0, 30); tft_setTextColor(ILI9341_WHITE); tft_setTextSize(1); tft_writeString("PWM period\n"); tft_setCursor(0, 60); tft_setTextColor(ILI9341_WHITE); tft_setTextSize(1); tft_writeString("ADC value\n"); tft_setCursor(70, 60); tft_setTextColor(ILI9341_WHITE); tft_setTextSize(1); tft_writeString("ADC value\n"); tft_setCursor(0, 90); tft_setTextColor(ILI9341_WHITE); tft_setTextSize(1); tft_writeString("Current Time\n"); tft_setCursor(0, 120); tft_setTextColor(ILI9341_WHITE); tft_setTextSize(1); tft_writeString("Current Date\n"); current_date.l = RtccGetDate(); tft_setCursor(0, 130); tft_setTextColor(ILI9341_YELLOW); tft_setTextSize(2); sprintf(buffer,"Date: %x/%x/%x", current_date.mon, current_date.mday, current_date.year); tft_writeString(buffer); while(1) { // yield time 1 second PT_YIELD_TIME_msec(100); //sys_time_seconds++ ; //read adc values adc0_prev = adc0; adc0 = readADC(11) + 20; adc1_prev = adc1; adc1 = readADC(5); //compare adc values diff = adc0 - adc1; if(diff > 10) pwm_period += 20; else if(diff < -10) pwm_period -= 20; if(pwm_period > 4500) pwm_period = 4500; else if(pwm_period < 0) pwm_period = 0; //pwm scaling pwm_prev = pwm; //pwm_period = adc0 * 4.5; pwm = 1500 + pwm_period; if(pwm > 6000) pwm = 6000; OC1RS = pwm; // draw sys_time // tft_fillRoundRect(0,10, 100, 14, 1, ILI9341_BLACK);// x,y,w,h,radius,color // tft_setCursor(0, 10); // tft_setTextColor(ILI9341_YELLOW); tft_setTextSize(2); // sprintf(buffer,"%d", sys_time_seconds); // tft_writeString(buffer); //save previous time prev_time = current_time; current_time.l = RtccGetTime(); //print pwm for debugging if(pwm_prev != pwm) { tft_fillRoundRect(0,40, 100, 14, 1, ILI9341_BLACK);// x,y,w,h,radius,color tft_setCursor(0, 40); tft_setTextColor(ILI9341_YELLOW); tft_setTextSize(2); sprintf(buffer,"%d", pwm); tft_writeString(buffer); } //print ADC0 value if(adc0_prev != adc0) { tft_fillRoundRect(0,70, 50, 14, 1, ILI9341_BLACK);// x,y,w,h,radius,color tft_setCursor(0, 70); tft_setTextColor(ILI9341_YELLOW); tft_setTextSize(2); sprintf(buffer,"%d", adc0); tft_writeString(buffer); } //print ADC0 value if(adc1_prev != adc1) { tft_fillRoundRect(70,70, 50, 14, 1, ILI9341_BLACK);// x,y,w,h,radius,color tft_setCursor(70, 70); tft_setTextColor(ILI9341_YELLOW); tft_setTextSize(2); sprintf(buffer,"%d", adc1); tft_writeString(buffer); } //print time value if(prev_time.l != current_time.l) { tft_fillRoundRect(0,100, 175, 14, 1, ILI9341_BLACK);// x,y,w,h,radius,color tft_setCursor(0, 100); tft_setTextColor(ILI9341_YELLOW); tft_setTextSize(2); sprintf(buffer,"Time: %x:%x:%x", current_time.hour, current_time.min, current_time.sec); tft_writeString(buffer); } // NEVER exit while } // END WHILE(1) PT_END(pt); } // timer thread // battery measure thread static PT_THREAD (protothread_battery_status(struct pt *pt)) { PT_BEGIN(pt); while(1) { // yield time PT_YIELD_TIME_msec(200); battery_level = getBatteryLevel(); updateLEDs(); if(battery_level < 700){ mPORTAClearBits(BACKLIGHT_PIN); PowerSaveSleep(); } else if(current_time.hour == initial_time.hour && current_time.min >= initial_time.min+time_till_night_mode && current_time.min <= initial_time.min+night_mode_duration) { clearLEDs(); mPORTAClearBits(BACKLIGHT_PIN); PowerSaveSleep(); } else{ mPORTASetBits(BACKLIGHT_PIN); } } PT_END(pt); } // battery measure thread // repeated sleep mode thread to perform tasks prior to putting device to sleep mode every 5 sec static PT_THREAD (protothread_sleep(struct pt *pt)) { PT_BEGIN(pt); while(1) { // yield time PT_YIELD_TIME_msec(5000); clearLEDs(); mPORTAClearBits(BACKLIGHT_PIN); PowerSaveSleep(); } PT_END(pt); } // sleep mode thread void __ISR(_RTCC_VECTOR, ipl2soft) RTCCInt(void){ //continue operation upon wakeup mRTCCClearIntFlag(); } /* * */ int main(int argc, char** argv) { SYSTEMConfigPerformance(PBCLK); count = 0; initial_time.l = initial_time_num; initial_date.l = initial_date_num; //initialize real time clock RtccInit(); RtccSetTimeDate(initial_time.l, initial_date.l); //setup rtcc alarm to repeat every 10 seconds RtccAlarmEnable(); RtccChimeEnable(); RtccSetAlarmTime(initial_time.l); RtccSetAlarmRpt(RTCC_RPT_TEN_SEC); //RtccSetAlarmRptCount(255); ANSELA = 0; ANSELB = 0; CM1CON = 0; CM2CON = 0; //battery status LED output pins mPORTBSetPinsDigitalOut(LED1_PIN | LED2_PIN | LED3_PIN | LED4_PIN); //Backlight control pin mPORTASetPinsDigitalOut(BACKLIGHT_PIN); //pull down resistor for pb input CNPDB = (1 << _CNPDB_CNPDB15_POSITION); PT_setup(); //enable settings for real time clock INTEnable(INT_RTCC, INT_ENABLED); INTSetVectorPriority(INT_RTCC_VECTOR, INT_PRIORITY_LEVEL_2); INTSetVectorSubPriority(INT_RTCC_VECTOR, INT_SUB_PRIORITY_LEVEL_0); // === setup system wide interrupts ======== INTEnableSystemMultiVectoredInt(); //RTCCIE_bit = 1; //enable clock RtccEnable(); // init the threads PT_INIT(&pt_battery_status); PT_INIT(&pt_sleep); PT_INIT(&pt_timer); //init peripherals initOC(); configureADC(); //initialize screen tft_init_hw(); tft_begin(); tft_setRotation(3); tft_fillScreen(ILI9341_BLACK); srand(1); while(1){ PT_SCHEDULE(protothread_timer(&pt_timer)); PT_SCHEDULE(protothread_battery_status(&pt_battery_status)); PT_SCHEDULE(protothread_sleep(&pt_sleep)); } return (EXIT_SUCCESS); }