/**
Included files
*/
#include "mcc_generated_files/mcc.h"
#include "lcd_jerry.h"
#include <stdio.h>
#include "app.h"
//************************* Defines and enums ******************
#define led_time 100 // 100ms update interval
#define lcd_time ((uint16_t)500) // 500ms update interval
#define adc_sample_time 10 // 10ms sample time
#define adc_update_time 100 // 100ms update interval
#define adc_channels 4
enum {
adc_idle = 0,
adc_sampling = 1,
adc_converting = 2,
adc_all_done = 3
} adc_status;
enum {
led_init = 0,
led_low = 1,
led_high = 2,
} led_status;
#define LED1 LATD1
#define LED2 LATD0
#define LED3 LATC3
#define LED4 LATC4
#define LED5 LATC5
#define LED6 LATC6
#define LED7 LATC7
#define LED8 LATB4
#define LED9 LATB3
#define LED10 LATB5
#define led_Toggle(n) { LED##n = !LED##n; }
#define led_On(n) { LED##n = 1; }
#define led_Off(n) { LED##n = 0; }
//************************* Global Variables ******************
uin32_t cell_voltages[4];
char volt_str[] = "1.11 V";
const uint16_t resistorRatioCell[4] = { 496, 367, 245, 123 };
const char digit[10] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
//************************* Functions ******************
void Handle_LED(void);
void Handle_LCD(void);
void Handle_ADC(void);
void LCD_Display(uint32_t cellVoltage, uint8_t row, uint8_t column);
void Lcd4_Clear(void);
void Lcd4_Init(void);
void configTimer0(void);
uint32_t getTime(void);
uint16_t readTimer0(void);
/*****************************************
Main application
*****************************************/
void main (void){
//Initialize functions
SYSTEM_Initialize(); // Timer0 Internal_clock, prescaler_32768, postscaler_1);
Lcd4_Init();
ADCC_Initialize();
APP_LED_Initialize();
// Enable the Global Interrupts
INTCONbits.GIE = 1;
// Enable the Peripheral Interrupts
INTCONbits.PEIE = 1;
// LCD Greeting
Lcd4_Clear();
Lcd4_Set_Cursor(1, 1);
Lcd4_Write_String("Battery");
Lcd4_Set_Cursor(2, 1);
Lcd4_Write_String("Simulation");
led4_Toggle();
__delay_ms(1500);
led4_Toggle();
Lcd4_Clear();
configTimer0();
while(1) {
Handle_LED();
Handle_ADC();
Handle_LCD();
}
}
void Handle_LED1(void)
{
static uint32_t last_time = 0;
static uint8_t status = 0;
/* Check the application's current state. */
uint32_t now = getTime();
uint32_t elapsed = last_time - now;
switch (status)
{
/* Application's initial state. */
case led_init:
{
led_Off(6); // Set LED off
status = led_low;
break;
}
case led_low:
{
if (elapsed < led_off_time)
{
return;
}
led_On(6); // Toggle LED On
status = led_high;
break;
}
case led_high:
{
if (elapsed < led_on_time)
{
return;
}
led_Off(6); // Toggle LED off
status = led_low;
break;
}
/* The default state should never be executed. */
default:
{
/* TODO: Handle error in application's state machine. */
break;
}
}
// last_time should be preserved for proper time tracking
// the program must return earlier if no action is done.
last_time = now;
}
void Handle_LED(void){
if ( elapsed < led_time){
return;
}
last_time = now;
// Do LED stuff
// Everytime you get here you know "led_time" time has passed
}
void Handle_ADC(void){
static uint32_t last_time = 0;
static uint8_t channel = 0;
static uint8_t status = adc_idle;
static uint32_t voltage[4];
uint32_t now = getTime();
uint32_t elapsed = last_time - now;
// Do ADC stuff
switch (status){
case adc_idle:
status++;
ADPCH = 5 - channel;
break;
case adc_sampling:
// wait for sampling time, but don't block program execution
if ( elapsed < adc_sample_time){
// Return now to avoid time update
return;
}
status++;
ADCON0bits.ADGO = 1;
break;
case adc_converting:
// If conversion done
if(!ADCON0bits.ADGO){
// Convert adc value to voltage
voltage[channel] = (((uint32_t)ADRESH << 8) | ADRESL) * 4 * resistorRatioCell[channel];
// Increase channel, check if all channels done
if ( ++channel >= adc_channels ){
// Reset channel index
channel = 0;
// Converts readings at the balance wires to individual cell voltage
for (uint8_t i = 0; i < 3; i++) {
cellVoltage[i] = voltage[i] - voltage[i+1];
}
status = adc_all_done;
}
else{
// Not done all channels yet, repeat
status = adc_idle;
}
}
break;
case adc_all_done:
// When all channels have been converted, wait the specified time for next conversion sequence
if ( elapsed < adc_update_time ){
// Return now to avoid time update
return;
}
// Time over, start over
status = adc_idle;
break;
}
last_time = now;
}
void Handle_LCD(void){
static uint32_t last_time = 0;
uint32_t now = getTime();
uint32_t elapsed = last_time - now;
if ( elapsed < lcd_time) ){
return;
}
last_time = now;
LCD_Display(cellVoltage[0], 1, 0);
LCD_Display(cellVoltage[1], 1, 8);
LCD_Display(cellVoltage[2], 2, 0);
LCD_Display(cellVoltage[3], 2, 8);
}
void LCD_Display(uint32_t cellVoltage, uint8_t row, uint8_t column) {
volt_str[0] = digit[ ((cellVoltage / 100000) % 10) ];
volt_str[2] = digit[ ((cellVoltage / 10000) % 10) ];
volt_str[3] = digit[ ((cellVoltage / 1000) % 10) ];
Lcd4_Set_Cursor(row, column);
Lcd4_Write_String(volt_str);
}
void configTimer0(void){
// Clear timer counters
TMR0H=0;
TMR0L=0;
// Set config (16bit, postscaler=1:1)
T0CON0 = 0x10;
// Configure clock (syncronized with FOSC/4, prescale = 1:8192, Clock=HFINTOSC/4)
// For 32MHz, F=8MHz, Timebase=8MHz/8192 = 1.024ms
T0CON1 = 0x4D;
// Enable timer
T0CON0bits.T0EN = 1;
}
uint16_t readTimer0(void) {
uint16_t time = TMR0L; // This order is critical,
time |= (uint16_t)TMR0H<<8; // TMR0L must be read first!
return time;
}
uint32_t getTime(void){
static uint32_t time = 0; // Full time storage
static uint16_t last = 0; // Previous timer (To detect overflow)
uint16_t current = readTimer0(); // Current timer value
if (last > current){ // If last>current, overflow ocurred
time += ((65536 - last) + current);
}
else{
time += ( current - last );
}
last = current;
return time;
}