Skip to content

Instantly share code, notes, and snippets.

@pleonex
Created November 28, 2013 02:58
Show Gist options
  • Save pleonex/7686642 to your computer and use it in GitHub Desktop.
Save pleonex/7686642 to your computer and use it in GitHub Desktop.
Ejercicio 6.3 de práctica 6 de la asignatura "Sistemas Electrónicos Digitales". Ejemplo de uso de microcontrolador PIC con periféricos usando I2C y RS232.
/****************************************************
** Ejercicio 6.3 - Práctica 6 - SED *
** *
** Programado por Benito Palacios Sánchez - 2013 *
****************************************************/
#include "../../lib/18F4520.h"
#device ADC=16
#fuses HS, WDT2048
#use delay(clock=8MHZ, restart_wdt)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, bits=8)
#include <ctype.h>
#include "../../lib/PCF8583.c"
#include "../../lib/2432.c"
#include "../../lib/FLOATEE.C"
#include "../../lib/LCDEasy.c"
#use fast_io(b)
#define LCD_COMMAND 0
#define LCD_CLEAR 1
#define LCD_HOME 2
#define ADC_MAX 65535
#define VOL_MAX 5
#define EEPROM_LENGTH 0x0FFF
#define BLOCK_LENGTH 0x000F
#define N_BLOCKS EEPROM_LENGTH / BLOCK_LENGTH
void procesa_comando();
void muestra_bytes_pos();
void muestra_bytes_long();
void muestra_byte(int16 dir);
void muestra_bloques_hora();
void muestra_bloques_fecha();
void muestra_bloques();
void muestra_datos_pos();
void muestra_datos_long();
void muestra_dato(int16 dir);
void muestra_media_poten();
void muestra_comandos();
int8 hex2int8(char c);
int16 hex2int16(char* hex);
// Variables de comando
char Comando[5];
char Argumentos[2][9];
int8 Idx_args = 0;
int8 Idx_escri = 0;
// Para saber si en esa posición hay datos o no.
int16 ultima_eepos = 0;
/*
Mediante el uso de interrupciones se puede despertar al PIC de su modo de bajo
consumo de forma que se puede obtener información en cualquier momento y no
hay que esperar a que el WDT lo despierte.
*/
#INT_RDA
void en_caracter_recibido() {
char c = getc();
if (c == '-') {
// Inicio del comando. Inicializa
memset(Comando, '\0', 5);
memset(Argumentos[0], '\0', 9);
memset(Argumentos[1], '\0', 9);
Idx_args = 0;
Idx_escri = 0;
} else if (c == ' ') {
// Argumento siguiente
Idx_escri = 0;
Idx_args++;
} else if (c == '\r') {
// Ejecuta el comando
procesa_comando();
} else if (c == '\n') {
// No hace nada, pues se envía junto a \r que ya se procesó
} else if (Idx_args == 0) {
// Escribiendo comando...
Comando[Idx_escri++] = c;
} else if (Idx_args == 1 || Idx_args == 2) {
// Escribiendo argumento...
Argumentos[Idx_args - 1][Idx_escri++] = c;
}
}
void procesa_comando() {
printf("Comando: %s | Arg0: %s | Arg1: %s\r\n", Comando, Argumentos[0],
Argumentos[1]);
switch (Comando) {
case "h": muestra_comandos(); break;
case "rsb": muestra_bloques(); break;
case "rsd": muestra_bytes_long(); break;
case "rsdi": muestra_datos_long(); break;
case "rsp": muestra_bytes_pos(); break;
case "rspi": muestra_datos_pos(); break;
case "rh": muestra_bloques_hora(); break;
case "rf": muestra_bloques_fecha(); break;
case "gmp": muestra_media_poten(); break;
default: printf("Comando no reconocido.\r\n");
}
}
void muestra_bytes_pos() {
int16 pos1 = hex2int16(Argumentos[0]);
int16 pos2 = hex2int16(Argumentos[1]);
for ( ; pos1 <= pos2 && pos1 < ultima_eepos; pos1++)
muestra_byte(pos1);
}
void muestra_bytes_long() {
int16 dir = hex2int16(Argumentos[0]);
int16 len = hex2int16(Argumentos[1]);
int16 i;
for (i = 0; i < len && dir + i < ultima_eepos; i++)
muestra_byte(dir + i);
}
void muestra_byte(int16 dir) {
printf("%4X: %2X\r\n", dir, read_ext_eeprom(dir));
}
void muestra_bloques_hora() {
int8 hora1 = (Argumentos[0][0] - '0') * 10 + (Argumentos[0][1] - '0');
int8 min1 = (Argumentos[0][3] - '0') * 10 + (Argumentos[0][4] - '0');
int8 seg1 = (Argumentos[0][6] - '0') * 10 + (Argumentos[0][7] - '0');
int8 hora2 = (Argumentos[1][0] - '0') * 10 + (Argumentos[1][1] - '0');
int8 min2 = (Argumentos[1][3] - '0') * 10 + (Argumentos[1][4] - '0');
int8 seg2 = (Argumentos[1][6] - '0') * 10 + (Argumentos[1][7] - '0');
int8 horat, mint, segt;
int16 pos, i;
for (pos = 11; pos < ultima_eepos; pos += BLOCK_LENGTH) {
horat = read_ext_eeprom(pos);
mint = read_ext_eeprom(pos + 1);
segt = read_ext_eeprom(pos + 2);
if ((hora1 < horat) || ((hora1 == horat) && (min1 < mint)) ||
((hora1 == horat) && (min1 == mint) && (seg1 <= segt))) {
break;
}
}
for ( ; pos < ultima_eepos; pos += BLOCK_LENGTH) {
for (i = pos - 11; i < pos - 11 + BLOCK_LENGTH && i < ultima_eepos; i++)
muestra_dato(i);
horat = read_ext_eeprom(pos);
mint = read_ext_eeprom(pos + 1);
segt = read_ext_eeprom(pos + 2);
if ((hora2 < horat) || ((hora2 == horat) && (min2 < mint)) ||
((hora2 == horat) && (min2 == mint) && (seg2 <= segt))) {
break;
}
}
}
void muestra_bloques_fecha() {
int8 dia1 = (Argumentos[0][0] - '0') * 10 + (Argumentos[0][1] - '0');
int8 mes1 = (Argumentos[0][3] - '0') * 10 + (Argumentos[0][4] - '0');
int8 anio1 = (Argumentos[0][6] - '0') * 10 + (Argumentos[0][7] - '0');
int8 dia2 = (Argumentos[1][0] - '0') * 10 + (Argumentos[1][1] - '0');
int8 mes2 = (Argumentos[1][3] - '0') * 10 + (Argumentos[1][4] - '0');
int8 anio2 = (Argumentos[1][6] - '0') * 10 + (Argumentos[1][7] - '0');
int8 diat, mest, aniot;
int16 pos, i;
for (pos = 8; pos < ultima_eepos; pos += BLOCK_LENGTH) {
aniot = read_ext_eeprom(pos);
mest = read_ext_eeprom(pos + 1);
diat = read_ext_eeprom(pos + 2);
if ((anio1 < aniot) || ((anio1 == aniot) && (mes1 < mest)) ||
((anio1 == aniot) && (mes1 == mest) && (dia1 <= diat))) {
break;
}
}
for ( ; pos < ultima_eepos; pos += BLOCK_LENGTH) {
for (i = pos - 8; i < pos - 8 + BLOCK_LENGTH && i < ultima_eepos; i++)
muestra_dato(i);
aniot = read_ext_eeprom(pos);
mest = read_ext_eeprom(pos + 1);
diat = read_ext_eeprom(pos + 2);
if ((anio2 < aniot) || ((anio2 == aniot) && (mes2 < mest)) ||
((anio2 == aniot) && (mes2 == mest) && (dia2 <= diat))) {
break;
}
}
}
void muestra_bloques() {
int16 pos1 = hex2int16(Argumentos[0]) * BLOCK_LENGTH;
int16 pos2 = hex2int16(Argumentos[1]) * BLOCK_LENGTH + BLOCK_LENGTH;
for ( ; pos1 < pos2 && pos1 < ultima_eepos; pos1++)
muestra_dato(pos1);
}
void muestra_datos_pos() {
int16 pos1 = hex2int16(Argumentos[0]);
int16 pos2 = hex2int16(Argumentos[1]);
for ( ; pos1 <= pos2 && pos1 < ultima_eepos; pos1++)
muestra_dato(pos1);
}
void muestra_datos_long() {
int16 dir = hex2int16(Argumentos[0]);
int16 len = hex2int16(Argumentos[1]);
int16 i;
for (i = 0; i < len && dir + i < ultima_eepos; i++)
muestra_dato(dir + i);
}
void muestra_dato(int16 dir) {
int8 b_pos = dir % BLOCK_LENGTH;
switch (b_pos) {
case 0:
printf("%4X: Voltaje 1 -> %.2f\r\n", dir, read_float_ext_eeprom(dir));
break;
case 1:
case 2:
case 3:
break; // Si no es desde la posición 0, no tienen sentido
case 4:
printf("%4X: Voltaje 2 -> %.2f\r\n", dir, read_float_ext_eeprom(dir));
break;
case 5:
case 6:
case 7:
break; // Si no es desde la posición 4, no tienen sentido
case 8:
printf("%4X: Anio 20%u\r\n", dir, read_ext_eeprom(dir));
break;
case 9:
printf("%4X: Mes %u\r\n", dir, read_ext_eeprom(dir));
break;
case 10:
printf("%4X: Dia %u\r\n", dir, read_ext_eeprom(dir));
break;
case 11:
printf("%4X: Hora %u\r\n", dir, read_ext_eeprom(dir));
break;
case 12:
printf("%4X: Minutos %u\r\n", dir, read_ext_eeprom(dir));
break;
case 13:
printf("%4X: Segundos %u\r\n", dir, read_ext_eeprom(dir));
break;
case 14:
printf("%4X: Dia de la semana %s\r\n", dir,
weekday_names[read_ext_eeprom(dir)]);
break;
}
}
void muestra_media_poten() {
int8 ult_bloque = ultima_eepos / BLOCK_LENGTH;
int16 i;
float suma1 = 0;
float suma2 = 0;
for (i = 0; i < ult_bloque; i++) {
suma1 += read_float_ext_eeprom(i * BLOCK_LENGTH);
suma2 += read_float_ext_eeprom(i * BLOCK_LENGTH + 4);
}
printf("Media voltaje 1: %.2f\r\n", suma1 / ult_bloque);
printf("Media voltaje 2: %.2f\r\n", suma2 / ult_bloque);
}
void muestra_comandos() {
printf("| Comandos |: \r\n");
printf(" -h Muestra comandos disponibles. \r\n");
printf(" -rsb ni n Lee secuencialmente 'n' bloques de\r\n");
printf(" datos partiendo del bloque 'ni'. \r\n");
printf(" -rsd p l Lee secuencialmente 'l' bytes de \r\n");
printf(" datos partiendo de 'p'. \r\n");
printf(" -rsdi p l Igual que '-rsd' pero interpreta \r\n");
printf(" (si es posible) los datos. \r\n");
printf(" -rsp p1 p2 Lee secuencialmente todos los \r\n");
printf(" datos entre 'p1' y 'p2' (p2 > p1).\r\n");
printf(" -rspi p1 p2 Igual que '-rsp' pero interpreta \r\n");
printf(" (si es posible) los datos. \r\n");
printf(" -rh h1 h2 Lee bloques entre las horas 'h1' y\r\n");
printf(" 'h2' (h2 > h1). Formato hh:mm:ss \r\n");
printf(" -rf f1 f2 Lee bloques entre las fechas 'f1' \r\n");
printf(" y 'f2' (f2 > f1). Formato dd/mm/aa\r\n");
printf(" -gmp Visualiza la media de todos los \r\n");
printf(" valores de potenciometro. \r\n");
printf("NOTA: Para 'rsb', 'rsd', 'rsdi', 'rsp' y 'rspi';\r\n");
printf("el formato de sus argumentos es XXXX (hex). \r\n");
}
void main() {
char weekday[10];
date_time_t dt;
int16 lectura;
float volt1_out;
float volt2_out;
int16 ee_pos = 0;
// Configuración del módulo reloj
PCF8583_init();
// Establece la hora actual
dt.year = 13;
dt.month = 11;
dt.day = 28;
dt.hours = 03;
dt.minutes = 15;
dt.seconds = 43;
dt.weekday = 4;
PCF8583_set_datetime(&dt);
// Configuración de conversor A-DC
setup_adc_ports(AN0_TO_AN3);
setup_adc(ADC_CLOCK_DIV_8);
// Configuración de interrupción
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
// Configuración de pantalla LCD
lcd_init();
lcd_send_byte(LCD_COMMAND, LCD_CLEAR);
// Mensaje inicial de bienvenida
printf(" Bienvenido al ejercicio 6.3 \r\n");
printf("Cada 8 seg. obtendra la hora en la pantalla LCD \r\n");
printf("junto al valor de los potenciometros. Ademas, \r\n");
printf("dispone de comandos extras para recibir mediante\r\n");
printf("RS232 informacion guardada en la EEPROM externa.\r\n");
muestra_comandos();
while (true) {
setup_wdt(WDT_ON);
sleep();
setup_wdt(WDT_OFF);
lcd_send_byte(LCD_COMMAND, LCD_CLEAR);
// Lee y muestra la fecha y hora
PCF8583_read_datetime(&dt);
strcpy(weekday, weekday_names[dt.weekday]);
printf(lcd_putc, "%s, %2u/%2u/%2u \nHora: %u:%2u:%2u ",
weekday, dt.day, dt.month, dt.year,
dt.hours, dt.minutes, dt.seconds);
delay_ms(1000);
// Obtiene y muestra el valor de los potenciómetros
set_adc_channel(2);
delay_us(10);
lectura = read_adc();
volt1_out = (float)lectura / ADC_MAX * VOL_MAX;
set_adc_channel(3);
delay_us(10);
lectura = read_adc();
volt2_out = (float)lectura / ADC_MAX * VOL_MAX;
lcd_send_byte(LCD_COMMAND, LCD_CLEAR);
printf(lcd_putc, "VOLT1: %.2f\nVOLT2: %.2f", volt1_out, volt2_out);
// Los guarda en la EEPROM en bloque consecutivo. De esta forma dada una
// dirección de memoria se puede saber qué tipo de dato hay grabado.
if (ee_pos + BLOCK_LENGTH > EEPROM_LENGTH)
ee_pos = 0;
write_float_ext_eeprom(ee_pos, volt1_out);
ee_pos += 4;
write_float_ext_eeprom(ee_pos, volt2_out);
ee_pos += 4;
write_ext_eeprom(ee_pos++, dt.year);
write_ext_eeprom(ee_pos++, dt.month);
write_ext_eeprom(ee_pos++, dt.day);
write_ext_eeprom(ee_pos++, dt.hours);
write_ext_eeprom(ee_pos++, dt.minutes);
write_ext_eeprom(ee_pos++, dt.seconds);
write_ext_eeprom(ee_pos++, dt.weekday);
// Actualiza la variable que contiene la última posición escrita.
if (ee_pos > ultima_eepos)
ultima_eepos = ee_pos;
}
}
int16 hex2int16(char* hex) {
int16 valor = 0;
int8 i = 0;
int8 j = 12;
while (hex[i] != '\0') {
valor |= (int16)hex2int8(hex[i]) << j;
i++;
j -= 4;
}
return valor;
}
int8 hex2int8(char hex) {
hex = toupper(hex);
if (hex >= '0' && hex <= '9')
return hex - '0';
else if (hex >= 'A' && hex <= 'F')
return hex - 'A' + 10;
else
return 0xFF;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment