Descripción.
El sistema electronico que se diseña, hace el control de un conjunto de semáforos (en este caso 4) en una intersección de 2 dos vías, ademas cuenta con un sistema de seguridad por software para evitar colisiones entre motorizados en cambios de estado de los semáforos, y también al igual para los semáforos peatonales, en este caso un parpadeo de color rojo como advertencia que el semáforo cambiara de estado.

P-B, P-A, son semáforos que controla la circulación de peatones en sus respectivas vías, y como se ya se supone V-A, V-B, controlan la circulación de los motorizados, de paso estos semáforos cuentan con sus respectivos contadores de tiempo.
Materiales.
  • 1 PIC16F877A
  • 2 capacitor 22pF
  • 1 cristal 4MHz
  • 2 transistores 2N3904 ó 2N2222
  • 4 leds rojo 
  • 2 leds amarillo
  • 4 leds verde
  • 2 display 7 segmentos de 2 dígitos cátodo común ó 4 display un dígito 
  • 24 resistencias 220 --- 470 ohm
  • 3 resistencias 4.7k --- 10k ohm
  • Cables para conexionado
  • Protoboars
  • Fuente de 5 volts 
Desarrollo.
PIC16F877A.
Este MCU cuenta con cuatro puertos RA, RB, RC y RD, con los cuales se hará el control de todos periféricos y la asignacion esta dada como sigue.
RD se controla el contador (display) del semaforo V-B.
RC se controla el contador (display) del semaforo V-A.
RB7, RB6 controla la multiplexacion delos digitos 1 y 2 de ambos displays.
RB5, RB4, RB3: verde, amarillo, rojo del semáforo V-B.
RB2, RB1, RB0: verde, amarillo, rojo del semáforo V-A.
RA3, RA2: verde, rojo semaforo P-A.
RA1, RA0: verde, rojo semaforo P-A.



Generación base de tiempo.
Con el TMR0 se puede generar interrupciones de tiempos cortos pero lo que se quiere es generar una interrupción cada segundo, para ello se genera una interrupción cada 2ms y con un conteo de 500 se hace 1 segundo, a continuacion la ecuecion de  calculo del valor a cargar en el TMR0.

El TMR0, es de 8 bits con lo cual se llega un conteo máximo de 0 a 255 de ahí el 256 en la ecuación,  se tiene 256 valores diferentes.

Codificación de display 7 segmentos cátodo común.
A continuación se aprecia los códigos en hexadecimal asociados a cada numero decimal que serán visibilizados por los displays.

si se trabaja con displays de ánodo común para generar su código hex los 0s serian asignados por 1s y 1s por 0s y los transistores que se encargaran a multiplexar tendrían que ser remplazados por transistores PNP como el 2N3906, también estaría cambiando la manera de conexionado de los displays con los transistores.

Diagrama circuital.
La mayoría de los componentes están conectados mediante uso de etiquetas (cada punto del circuito que lleva un nombre tiene su gemelo en otra parte con el mismo nombre "estos están conectados"). 
Se debe añadir un capacitor de 100nF en paralelo a la fuente de alimentacion, esto con el objetivo de eliminar ruidos que pueden afectar en el funcionamiento del circuito. 



Codigo escrito en PIC C compiler (CCS)

/*Semaforo con contador regresivo
 *Universidad: UMSS (FCYT)
 *Carrera: Ing. Electronica
 *Autor : Univ. Puente C. Javier (JaviP)
 *Fecha: 1-1-2020
*/
#include<16f877a.h>
#fuses NOWDT,XT,NODEBUG,NOLVP,NOPUT,BROWNOUT// Fusibles
#use delay(clock=4M)//Frecuencia defuncionamiento
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
int1 x=1;
int16 s=0;
const int8 Tr=15,Ta=3,Tv=Tr-Ta;//Constantes de Tiempo  
//arreglo de codigo hexadecimal para los displays
const int8 disp[11]= {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00};
#int_timer0   //interrupcion cada 2ms
void timer0(){//Funcion interrupcion y contador s=500 entonces 1 segundo
 s++;
 set_timer0(131); //carga o valor del TMR0
}
void parada();//Funcion de seguridad, evita el cambio instantáneo de rojo a verde
void display(int8 A,int8 B);// Funcion contador y multiplexacion de los displays
void main(){//Funcion Principal
  setup_timer_0(T0_INTERNAL|T0_DIV_16);// preescaler de 16 
  SET_TIMER0(131);  //carga o valor del TMR0
  ENABLE_INTERRUPTS (INT_TIMER0); //habilitacion interrupsion del TMR0
  ENABLE_INTERRUPTS (GLOBAL); habilitacion interrupsion global
  set_tris_a(0x00); // puertos como salida
  set_tris_b(0x00);
  set_tris_c(0x00);
  set_tris_d(0x00);
  output_a(0x00); // escritura en los puertos de un estado bajo, 0
  output_b(0x00);
  output_c(0x00);
  output_d(0x00);
 while(1){// Ciclo Infinito
  parada(); // llamada de funcion parada
  int8 a=Tr; 
  if(x==1){ 
  output_high(pin_b0);
  output_high(pin_b5);
  output_high(pin_a3);
  output_high(pin_a0);
  for(int j=Tv;j>0;j--){
  display(a,j-1);// llamada a funcion display
  a--;
  }
  output_low(pin_b5);
  output_high(pin_b4);
  output_low(pin_a3);
  for(int k=Ta+1;k>0;k--){
  output_toggle(pin_a2);
  display(a,k-1);
  a--;
  }
  x=0;
  }else{
  output_high(pin_b3);
  output_high(pin_b2);
  output_high(pin_a1);
  output_high(pin_a2);
  for(int j=Tv;j>0;j--){
  display(j-1,a);
  a--;
  }
  output_low(pin_b2);
  output_high(pin_b1);
  output_low(pin_a1);
  for(int k=Ta+1;k>0;k--){
  output_toggle(pin_a0);
  display(k-1,a);
  a--;
  }
  x=1;
  }
  }
  }
//para toda la circulacion , semaforos en rojo por un tiempo determinado
void parada(){
 output_b(0x09);
 output_a(0x05);
 delay_ms(500);//Tiempo de parada
 output_b(0x00);
 output_a(0x00);
}
//muestra en el display un numero durante 1 segundo
void display(int8 A,int8 B){// como dato recibe tiempos para el display A y B
int8 digit1A,digit2A,digit1B,digit2B;
if(A>9){//divide en numero en unidad y decena para display A
 digit2A=A%10;
 digit1A=(A-digit2A)/10;
}else{// elimina el 0 por delante cuando el tiempo es menor a 10 en display A
digit1A=10;
digit2A=A;
}
if(B>9){ //divide en numero en unidad y decena para display B
 digit2B=B%10;
 digit1B=(B-digit2B)/10;
}else{ //elimina el 0 por delante cuando el tiempo es menor a 10 en display B
digit1B=10;
digit2B=B;
}
s=0;// el contador en 0
while(s<500){ //inicia la muestra del tiempo durante un segundo en los displays 
output_low(pin_b7);
output_c(0x00);
output_d(0x00);
output_high(pin_b6);
output_c(disp[digit1A]);
output_d(disp[digit1B]);
delay_ms(5); // tiempo de multiplexación
output_low(pin_b6);
output_c(0x00);
output_d(0x00);
output_high(pin_b7);
output_c(disp[digit2A]);
output_d(disp[digit2B]);
delay_ms(5); // tiempo de multiplexación
}
}

Video.
En el siguiente vídeo se hace una explicación un poco mas a fondo sobre la ejecución del código como también los resultados(funcionamiento) finales del sistema electrónico.




Descargas.

Descarga, código en .c y .txt , simulación en proteus 8.8 (en versiones inferiores no se podrá ejecutar), archivo compilado .hex
Opción 1


Opción 2