Horloge pilotée par GPS

C'est une alternative aux horloges et montres pilotées par DCF77, tout le monde ne résidant pas dans un rayon de 500km de la ville allemande de Francfort. Cette horloge est pilotée par un petit récepteur GPS (un module NEO-6M) qui se synchronise sur les satellites du "Global Positioning System" américain, mais j'ai bien l'intention de le faire fonctionner un jour prochain avec le système Galileo.

1 Le proto 100% fonctionnel :

31 décembre 2015:
Je ne présente plus le module NEO-6M, visible en haut à droite, je l'ai déjà fait en détail pour mon générateur VHF 1Hz à 120MHz. Le microcontrôleur est un ATmega8, en version DIL sur ce proto, et CMS pour la version définitive.

2 Le schéma :

La sortie TX (RS232) du NEO-6M est reliée à l'entrée RX de l'Atmega. C'est par ce biais que sont transmises les informations donnant l'heure précise, suivant le protocole NMEA. (informations dénommées "GPZDA" = date and time) Toutefois ces infos ZDA ne sont pas émises par défaut par le NEO-6M, seules les informations GPGLL (latitude-longitude) le sont. Il faut paramétrer le NEO-7M (avec le logiciel windows "u-center") pour qu'il sorte ces ZDA. On peut ensuite, toujours à l'aide du logiciel u-center faire en sorte que ce paramétrage soit mémorisé en RAM interne alimentée par un accu lilliputien présent sur le module, ce qui signifie que ces infos sont en fait perdues si le module n'est pas alimenté pendant un ou deux jours... Solution : ré-paramétrer correctement le NEO-6M automatiquement à chaque mise en service, et sans utiliser le logiciel windows u-center. Et il se trouve que l'ATmega s’acquitte fort bien de cette tâche ! Et c'est la raison d'être de la seconde liaison entre le TX de l'ATmega et le RX du NEO-6M.

3 Modes d'affichages

Un inverseur (le petit switch soudé au bout des fils à gauche sur la photo principale) permet de basculer entre deux modes d'affichages :
  • Heures et minutes seulement avec des gros chiffres
  • Heure minutes secondes + date et jour de la semaine
Le jour de la semaine est calculé par l'ATmega, par une fonction basée sur l'Algorithme de Mike Keith.

4 Le firmware :

CODE SOURCE en C
  1. /**
  2. Horloge GPS
  3. Version A du firmware -> pour afficheur LCD 2x16c
  4. **/
  5.  
  6. #define F_CPU 16000000
  7.  
  8. #include <util/delay.h>
  9. #include <avr/io.h>
  10. #include <stdint.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <avr/interrupt.h>
  14. #include <avr/sleep.h>
  15.  
  16.  
  17. #include "dm_lcd3.cpp" // l'attribution des pins/ports pour le LCD (et le type de LCD) est faite dans le fichier dm_lcd.h
  18. #include "LCD_gros_chiffres2_628.c"
  19. #include "uart_628.c"
  20.  
  21.  
  22. char version[] = "version 2.5";
  23.  
  24. uint8_t heure, minute, seconde;
  25. uint8_t annee_ok, heure_ok, minute_ok, seconde_ok;
  26. uint8_t jour, mois;
  27. uint16_t annee;
  28. uint8_t jour_de_la_semaine;
  29. uint8_t octet_recu;
  30. uint8_t buffer232[100];
  31. uint16_t compteur1;
  32. uint8_t a_effacer;
  33.  
  34.  
  35.  
  36.  
  37. void init_ports (void) // ports perso
  38. // 0 = entree, 1=sortie ; les 1 sur les pins en entrees activent les R de Pull Up (tirage à VCC)
  39. {
  40. DDRB |= 0b11111111;
  41. PORTB = 0b00000000;
  42.  
  43. DDRC = 0b11111111; // bit4=SDA ; bit5=SLC
  44. PORTC = 0b00000000;
  45.  
  46. DDRD = 0b11101110; // PD0 = entree RXD; PD4 = switch
  47. PORTD = 0b00010000;
  48. }
  49.  
  50.  
  51. void InitINTs (void)
  52. {
  53.  
  54. }
  55.  
  56.  
  57. void init_variables(void)
  58. {
  59. compteur1 = 0;
  60. heure = 0;
  61. minute=0;
  62. seconde=0;
  63. jour =0;
  64. mois=0;
  65. annee=0;
  66. a_effacer =1;
  67. }
  68.  
  69.  
  70.  
  71. void init_lcd()
  72. {
  73. uint8_t i;
  74.  
  75. lcd_init(LCD_DISP_ON_CURSOR); // cursor on
  76. //cd_init(LCD_DISP_ON); // cursor off
  77.  
  78. lcd_clrscr();
  79. }
  80.  
  81.  
  82.  
  83. void lcd_gotoxy_clrEOL (int x, int y)
  84. // place le curseur en x,y et efface jusqu'à la fin de la ligne
  85. {
  86. lcd_gotoxy(x, y);
  87. uint8_t i;
  88. for (i=x; i<20; i++){ lcd_puts(" "); }
  89. lcd_gotoxy(x, y);
  90. }
  91.  
  92.  
  93.  
  94.  
  95.  
  96.  
  97. void lcd_aff_nb (uint32_t valeur, uint8_t nb_chiffres, uint8_t nb_decimales, uint8_t affi_zeros)
  98. {
  99. //affiche un nombre en representation decimale
  100. // affi_zeros = 1 affiche les zéros non significatifs à gauche.
  101. unsigned char r ;
  102. char tbl[7];
  103. char digit;
  104. uint8_t i;
  105.  
  106. for (i=1; i<=nb_chiffres; i++)
  107. {
  108. r=48 + valeur % 10; // modulo (reste de la division)
  109. valeur /= 10; // quotient
  110. tbl[i]=r;
  111. }
  112. uint8_t debut = 1-affi_zeros; // pour ne pas afficher des zeros à gauche du 1er chiffre
  113. for (i=1; i<=nb_chiffres; i++)
  114. {
  115. if (i== (nb_chiffres - nb_decimales +1) ) { lcd_puts("."); }
  116. digit = tbl[nb_chiffres +1 -i];
  117. if (digit != '0') {debut = 0;}
  118. if ((digit != '0') || (debut == 0)) {lcd_putc(digit);}
  119. }
  120. }
  121.  
  122.  
  123. void lcd_aff_nb_relatif (int16_t valeur, uint8_t nb_chiffres, uint8_t nb_decimales)
  124. {
  125. //affiche un nombre relatif (c.a.d positif ou négatif) en representation decimale
  126. unsigned char r ;
  127. char tbl[7];
  128. char digit;
  129. uint8_t i;
  130. uint8_t affi_zeros = 1; // affi_zeros = 1 affiche les zéros non significatifs à gauche.
  131.  
  132. if (valeur <0)
  133. {
  134. valeur = -valeur;
  135. lcd_putc('-');
  136. }
  137. else
  138. {
  139. lcd_putc('+');
  140. }
  141.  
  142. for (i=1; i<=nb_chiffres; i++)
  143. {
  144. r=48 + valeur % 10; // modulo (reste de la division)
  145. valeur /= 10; // quotient
  146. tbl[i]=r;
  147. }
  148. uint8_t debut = 1-affi_zeros; // pour ne pas afficher des zeros à gauche du 1er chiffre
  149. for (i=1; i<=nb_chiffres; i++)
  150. {
  151. if (i== (nb_chiffres - nb_decimales +1) ) { lcd_puts("."); }
  152. digit = tbl[nb_chiffres +1 -i];
  153. if (digit != '0') {debut = 0;}
  154. if ((digit != '0') || (debut == 0)) {lcd_putc(digit);}
  155. }
  156. }
  157.  
  158.  
  159.  
  160. void lcd_aff_nb_form3 (uint32_t valeur, uint8_t nb_chiffres)
  161. {
  162. //affiche un nombre en representation decimale en separant les groupes de 3 chiffres
  163. unsigned char r ;
  164. char tbl[7];
  165. uint8_t i;
  166.  
  167. for (i=1; i<=nb_chiffres; i++)
  168. {
  169. r=48 + valeur % 10; // modulo (reste de la division)
  170. valeur /= 10; // quotient
  171. tbl[i]=r;
  172. }
  173. for (i=1; i<= nb_chiffres; i++)
  174. {
  175. if ((((i-1) % 3) == 0 ) && (i>1)) { lcd_puts("."); }
  176. lcd_putc(tbl[nb_chiffres +1 -i]);
  177. }
  178. }
  179.  
  180.  
  181.  
  182. void lcd_aff_bin (uint16_t valeur, uint8_t nb_digits)
  183. {
  184. //affiche un nombre en representation binaire
  185. // 16 bits max
  186. uint8_t r ;
  187. char tbl[17];
  188. uint8_t i;
  189.  
  190. for (i=1; i<=nb_digits; i++)
  191. {
  192. r= 48 + valeur % 2; // modulo (reste de la division)
  193. valeur /= 2; // quotient
  194. tbl[i]=r;
  195. };
  196.  
  197. for (i=1; i<=nb_digits; i++)
  198. {
  199. lcd_putc(tbl[nb_digits +1 -i]);
  200. }
  201. }
  202.  
  203.  
  204. void lcd_aff_hexa(uint16_t valeur, int nb_signes)
  205. {
  206. //affiche un nombre en representation hexadécimale
  207. // 16 nb_signes hexa max
  208. unsigned char r ;
  209. char tbl[17];
  210. char signes[17] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
  211. uint8_t i;
  212.  
  213. for (i=1; i<=nb_signes; i++)
  214. {
  215. r= valeur % 16; // modulo (reste de la division)
  216. valeur /= 16; // quotient
  217. tbl[i]=signes[r];
  218. };
  219.  
  220. for (i=1; i<=nb_signes; i++)
  221. {
  222. lcd_putc(tbl[nb_signes +1 -i]);
  223. }
  224. //lcd_putc('h');
  225. }
  226.  
  227.  
  228.  
  229. // lcd_aff_nb (valeur, nb_chiffres, nb_decimales, affi_zeros)
  230. void affiche_heure()
  231. {
  232. lcd_gotoxy_clrEOL (0, 0);
  233. lcd_aff_nb(heure, 2, 0, 1);
  234. lcd_gotoxy(2, 0);
  235. lcd_putc(':');
  236. lcd_gotoxy(3, 0);
  237. lcd_aff_nb(minute, 2, 0, 1);
  238. lcd_gotoxy(5, 0);
  239. lcd_putc(':');
  240. lcd_gotoxy(6, 0);
  241. lcd_aff_nb(seconde, 2, 0, 1);
  242. }
  243.  
  244.  
  245. void affiche_heure_BIG()
  246. {
  247. uint8_t h_u, h_d, mn_u, mn_d;
  248.  
  249.  
  250. if(a_effacer == 1) {lcd_clrscr(); a_effacer = 0;}
  251.  
  252. mn_d = minute / 10;
  253. mn_u = minute % 10;
  254.  
  255. h_d = heure / 10;
  256. h_u = heure % 10;
  257.  
  258. if(h_d >0) { lcd_affi_Gros_Chiffre(h_d, 0);} else { lcd_efface_Gros_Chiffre(0); }
  259. lcd_affi_Gros_Chiffre(h_u, 4);
  260.  
  261. if((seconde % 2) == 0) {seperateur(7);} else {lcd_efface_Gros_Chiffre(7);}
  262.  
  263. lcd_affi_Gros_Chiffre(mn_d, 9);
  264. lcd_affi_Gros_Chiffre(mn_u, 13);
  265. }
  266.  
  267.  
  268. void affiche_date()
  269. {
  270.  
  271. lcd_gotoxy_clrEOL (0, 1);
  272. if (annee_ok == 1)
  273. {
  274. lcd_aff_nb(jour, 2, 0, 1);
  275. lcd_gotoxy(2, 1);
  276. lcd_putc('-');
  277. lcd_gotoxy(3, 1);
  278. lcd_aff_nb(mois, 2, 0, 1);
  279. lcd_gotoxy(5, 1);
  280. lcd_putc('-');
  281. lcd_gotoxy(6, 1);
  282. lcd_aff_nb(annee, 4, 0, 1);
  283.  
  284. lcd_gotoxy(11, 1);
  285.  
  286. //lcd_aff_nb(jour_de_la_semaine, 2, 0, 1);
  287. char jours[7][3] = { {'D', 'I', 'M'},{'L', 'U', 'N'},{'M', 'A', 'R'},{'M', 'E', 'R'},{'J', 'E', 'U'},{'V', 'E', 'N'},{'S', 'A', 'M'}};
  288.  
  289. uint8_t i;
  290. for (i=0; i<3; i++) {lcd_putc(jours[jour_de_la_semaine][i]);}
  291. }
  292. else
  293. {
  294. lcd_gotoxy(2, 1);
  295. lcd_puts("Att date ok");
  296. }
  297. }
  298.  
  299.  
  300.  
  301.  
  302. void RAZ_buffer()
  303. {
  304. uint8_t i;
  305. for (i=0; i<40; i++)
  306. {
  307. buffer232[i]=' ';
  308. }
  309. }
  310.  
  311.  
  312. void affiche_buffer232()
  313. {
  314. uint8_t n;
  315.  
  316. //lcd_gotoxy_clrEOL(0,1);
  317. for(n=0; n<16; n++)
  318. {
  319. lcd_gotoxy(n, 0);
  320. lcd_putc(buffer232[n]);
  321. }
  322.  
  323. for(n=0; n<16; n++)
  324. {
  325. lcd_gotoxy(n, 1);
  326. lcd_putc(buffer232[n+16]); // +16 ou +24 ou +32 suivant ce qu'on veut explorer
  327. }
  328.  
  329. }
  330.  
  331.  
  332.  
  333. void affiche_buffer232_hex()
  334. {
  335. uint8_t n, i;
  336.  
  337. lcd_gotoxy_clrEOL(0,0);
  338. for(n=0; n<8; n++)
  339. {
  340. // affiche les 8 premiers octets sur la première ligne
  341. lcd_gotoxy(2*n, 0);
  342. lcd_aff_hexa(buffer232[n+8], 2);
  343. }
  344.  
  345. lcd_gotoxy_clrEOL(0,1);
  346. for(n=0; n<10; n++)
  347. {
  348. // affiche les 8 octets suivants sur la seconde ligne
  349. lcd_gotoxy(2*n, 1);
  350. lcd_aff_hexa(buffer232[n+16], 2);
  351. }
  352.  
  353. }
  354.  
  355.  
  356. void decode_message_horaire()
  357. {
  358. heure_ok =0;
  359. minute_ok=0;
  360. seconde_ok=0;
  361. heure = buffer232[7] -48 + 10*(buffer232[6] -48) +1; //pour la France -> +1 (heure d'hiver) ou +2 (heure d'été)
  362. if (heure <24) {heure_ok = 1;}
  363. minute = buffer232[9] -48 + 10*(buffer232[8] -48);
  364. if (heure <60) {minute_ok = 1;}
  365. seconde= buffer232[11] -48 + 10*(buffer232[10] -48);
  366. if (seconde <60) {seconde_ok = 1;}
  367.  
  368. // heure =seconde; // <- pratique pour tester affichage gros chiffres
  369.  
  370. jour = 0;
  371. mois = 0;
  372.  
  373. jour = buffer232[17] -48 + 10*(buffer232[16] -48);
  374. mois = buffer232[20] -48 + 10*(buffer232[19] -48);
  375.  
  376. annee = 0;
  377. annee_ok = 0;
  378. annee = buffer232[25] -48 + 10*(buffer232[24] -48) + 100*(buffer232[23] -48) + 1000*(buffer232[22] -48);
  379. if ((annee >0)&&(annee < 2100)) {annee_ok = 1;}
  380. }
  381.  
  382.  
  383.  
  384. void calcul_jour_de_la_semaine()
  385. {
  386. // d'après l'Algorithme de Mike Keith
  387. uint16_t d, m, y, z, jds;
  388.  
  389. d=jour;
  390. m=mois;
  391. y=annee;
  392.  
  393. if (m>=3)
  394. {
  395. jds = ( ((23*m)/9) + d + 4 + y + (y/4) - (y/100) + (y/400) - 2 ) % 7;
  396. }
  397. else
  398. {
  399. z = y-1;
  400. jds = ( ((23*m)/9) + d + 4 + y + (z/4) - (z/100) + (z/400) ) % 7;
  401. }
  402. jour_de_la_semaine = jds;
  403.  
  404. }
  405.  
  406. /**
  407.  Le message à transmettre au module NEO-6M peut-être affiché par u-center
  408.  -ouvrir le fenêtre Messages (par F9 ou menu View / Messages View)
  409.  -choisir dans la liste la fonction à programmer (ici: UBX / CFG(config/MSG(Messages)
  410.  -puis dans la liste déroulante qui apparait alors dans la partie droite de la fenêtre 'Messages, selectionner 'F0-08 NMEA GxZDA'
  411.  -le message à transmettre s'affiche alors dans le cadre au dessous.
  412.  
  413.  pour UBX-CFG(config)-MSG(Messages) = F0-08 NMEA GxZDA et UART1=on
  414.  envoyé par u-centre -> B5 62 06 01 08 00 F0 08 00 01 00 00 00 00 08 60
  415.  
  416.  B5 62 c'est l'entete toujours la même
  417.  06 01 -> CFG-MSG
  418.  08 00 -> LENGTH (=8 bytes)
  419.  F0 08 c'est la commande ZDA (F0 = class, 08 = ID)
  420.  00 01 00 00 code pour UART1=on
  421.  00 00 08 60 à la fin nous donne le checksum qui convient
  422.  
  423.  Nous allons tranmettre ces 16 octets au module NEO-6M avec l'USART de l'ATmega, ce qui nous permettra pas la suite de nous passer du programme u-center
  424. **/
  425. void config_NEO_6M_GPS()
  426. {
  427. //configure le recepteur GPS NEO-6M afin qu'il emette les informations horaires ("ZDA") sur son port RS232
  428. // ce qui n'est pas le cas par défaut
  429. uint8_t i;
  430.  
  431. uint8_t paquet[]={0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x08,0x00,0x01,0x00,0x00,0x00,0x00,0x08,0x60 };
  432.  
  433. for (i=0; i<16; i++)
  434. {
  435. USART_TxByte(paquet[i]);
  436. }
  437. }
  438.  
  439.  
  440.  
  441.  
  442. int main()
  443. {
  444. uint8_t i, n;
  445. uint8_t caract_i;
  446.  
  447. init_variables();
  448.  
  449. init_ports();
  450. InitINTs();
  451. init_lcd();
  452. cree_carateres();
  453.  
  454. USART_Init();
  455.  
  456. lcd_clrscr();
  457. lcd_puts("Horloge GPS");
  458. lcd_gotoxy(0,1);
  459. lcd_puts(version);
  460. _delay_ms(1000);
  461.  
  462.  
  463. lcd_command(LCD_DISP_ON); // cursor off
  464.  
  465. lcd_clrscr();
  466.  
  467.  
  468. affiche_heure();
  469.  
  470. // sei(); // enable interruptions
  471.  
  472. _delay_ms(1000);
  473. lcd_clrscr();
  474.  
  475. lcd_gotoxy(0,1);
  476. lcd_puts("config ZDA GPS");
  477.  
  478. config_NEO_6M_GPS();
  479.  
  480. _delay_ms(1000);
  481.  
  482. lcd_clrscr();
  483.  
  484. lcd_gotoxy(0,1);
  485. lcd_puts("Att signal GPS");
  486.  
  487. while(1)
  488. {
  489. i=0;
  490. octet_recu=0;
  491. RAZ_buffer();
  492.  
  493.  
  494. /**
  495. caract_i = 0xB5; while (octet_recu != caract_i) { octet_recu=USART_RxByte(); }
  496. buffer232[0] = caract_i;
  497.  
  498. n=1;
  499. octet_recu ='-';
  500. while ((octet_recu != 0x0A) && (n<26))
  501. {
  502.   octet_recu=USART_RxByte();
  503.   buffer232[n]=octet_recu;
  504.   n++;;
  505. }
  506. **/
  507. //char debut_message[5]= {'G','P','G','L','L'};
  508. char debut_message[5]= {'G','P','Z','D','A'};
  509.  
  510. caract_i = debut_message[0]; while (octet_recu != caract_i) { octet_recu=USART_RxByte(); } buffer232[i]=caract_i; i+=1;
  511.  
  512. caract_i = caract_i = debut_message[1]; octet_recu=USART_RxByte(); if( octet_recu == caract_i)
  513. {
  514. buffer232[i]=caract_i; i+=1; caract_i = debut_message[2]; octet_recu=USART_RxByte();
  515. if( octet_recu == caract_i)
  516. {
  517. buffer232[i]=caract_i; i+=1; caract_i = debut_message[3]; octet_recu=USART_RxByte();
  518. if( octet_recu == caract_i)
  519. {
  520. buffer232[i]=caract_i; i+=1; caract_i = debut_message[4]; octet_recu=USART_RxByte();
  521. if( octet_recu == caract_i)
  522. {
  523. buffer232[i]=caract_i; i+=1;
  524.  
  525. for (n=i; n<33; n++) // 33 ou 65 suivant ce qu'on veut lire
  526. {
  527. octet_recu=USART_RxByte();
  528. buffer232[n]=octet_recu;
  529. }
  530.  
  531. //affiche_buffer232();
  532.  
  533. decode_message_horaire();
  534. if ((heure_ok==1) && (minute_ok==1) && (seconde_ok==1))
  535. {
  536. if ((PIND & 0b00010000) !=0 )
  537. {
  538. calcul_jour_de_la_semaine();
  539. affiche_heure();
  540. affiche_date();
  541. a_effacer = 1;
  542. }
  543. else
  544. {
  545. affiche_heure_BIG();
  546. }
  547.  
  548. }
  549.  
  550. }
  551. }
  552. }
  553. }
  554.  
  555. //affiche_buffer232();
  556. //affiche_buffer232_hex();
  557.  
  558. compteur1--;
  559. if (compteur1 == 0)
  560. {
  561. compteur1 = 100;
  562. }
  563.  
  564. _delay_ms(20);
  565.  
  566. }
  567.  
  568. }
  569.  
  570.  
  571.  
  572.  
  573.  

CODE SOURCE en C
  1. /************************************************************************************
  2. LCD_gros_chiffres_628.c
  3. pour LCD 2x16 à Controller/Driver (HD44780)
  4.  
  5. Ce code ci-dessous est inspiré du travail de " Written by Isaac A. on Dec. 9, 2014 "
  6. Le principe est repris à l'identique, les chiffres ont été redessinés (plus arrondis)
  7.  
  8. Silicium628 - 30 décembre 2015
  9. *************************************************************************************/
  10.  
  11. // commands
  12. #define LCD_SET_CG_RAM_ADDR 0x40
  13.  
  14. uint8_t bottom[8] =
  15. {
  16. 0b00000,
  17. 0b00000,
  18. 0b00000,
  19. 0b00000,
  20. 0b00000,
  21. 0b11111,
  22. 0b11111,
  23. 0b11111
  24. };
  25.  
  26. uint8_t top[8] =
  27. {
  28. 0b11111,
  29. 0b11111,
  30. 0b11111,
  31. 0b00000,
  32. 0b00000,
  33. 0b00000,
  34. 0b00000,
  35. 0b00000
  36. };
  37.  
  38. uint8_t fill[8] =
  39. {
  40. 0b11111,
  41. 0b11111,
  42. 0b11111,
  43. 0b11111,
  44. 0b11111,
  45. 0b11111,
  46. 0b11111,
  47. 0b11111
  48. };
  49.  
  50. uint8_t leftcircle[8] =
  51. {
  52. 0b00000,
  53. 0b00000,
  54. 0b00001,
  55. 0b00011,
  56. 0b00011,
  57. 0b00001,
  58. 0b00000,
  59. 0b00000
  60. };
  61.  
  62. uint8_t rightcircle[8] =
  63. {
  64. 0b00000,
  65. 0b00000,
  66. 0b10000,
  67. 0b11000,
  68. 0b11000,
  69. 0b10000,
  70. 0b00000,
  71. 0b00000
  72. };
  73.  
  74. uint8_t topandbottom[8] =
  75. {
  76. 0b11111,
  77. 0b11111,
  78. 0b00000,
  79. 0b00000,
  80. 0b00000,
  81. 0b00000,
  82. 0b11111,
  83. 0b11111
  84. };
  85.  
  86.  
  87.  
  88. void lcd_cree_1_char(uint8_t location, uint8_t charmap[])
  89. {
  90. uint8_t i;
  91. location &= 0x7; // il y a 8 locations 0-7
  92. lcd_command(LCD_SET_CG_RAM_ADDR | (location << 3));
  93. for (i=0; i<8; i++) { lcd_putc(charmap[i]);}
  94. }
  95.  
  96.  
  97. void cree_carateres()
  98. {
  99. lcd_cree_1_char(0, bottom);
  100. lcd_cree_1_char(1, top);
  101. lcd_cree_1_char(2, fill);
  102. lcd_cree_1_char(3, leftcircle);
  103. lcd_cree_1_char(4, rightcircle);
  104. lcd_cree_1_char(5, topandbottom);
  105.  
  106. }
  107.  
  108.  
  109.  
  110. void espace(int pos)
  111. {
  112. lcd_gotoxy(pos, 0); lcd_puts(" ");
  113. lcd_gotoxy(pos + 1, 0); lcd_puts(" ");
  114. lcd_gotoxy(pos, 1); lcd_puts(" ");
  115. lcd_gotoxy(pos + 1, 1); lcd_puts(" ");
  116. }
  117.  
  118. void seperateur(int pos)
  119. {
  120. lcd_gotoxy(pos, 0); lcd_putc(3);
  121. lcd_gotoxy(pos + 1, 0); lcd_putc(4);
  122. lcd_gotoxy(pos, 1); lcd_putc(3);
  123. lcd_gotoxy(pos + 1, 1); lcd_putc(4);
  124. }
  125.  
  126. void zero(int pos)
  127. {
  128. lcd_gotoxy(pos, 0);
  129. lcd_putc((uint8_t)2);
  130. lcd_gotoxy(pos, 1);
  131. lcd_putc((uint8_t)2);
  132. lcd_gotoxy(pos + 1, 0);
  133. lcd_putc((uint8_t)1);
  134. lcd_gotoxy(pos + 1, 1);
  135. lcd_putc((uint8_t)0);
  136. lcd_gotoxy(pos + 2, 0);
  137. lcd_putc((uint8_t)2);
  138. lcd_gotoxy(pos + 2, 1);
  139. lcd_putc((uint8_t)2);
  140. }
  141.  
  142. void un(int pos)
  143. {
  144. lcd_gotoxy(pos, 0);
  145. lcd_putc((uint8_t)1);
  146. lcd_gotoxy(pos, 1);
  147. lcd_putc((uint8_t)0);
  148. lcd_gotoxy(pos + 1, 0);
  149. lcd_putc((uint8_t)2);
  150. lcd_gotoxy(pos + 1, 1);
  151. lcd_putc((uint8_t)2);
  152. lcd_gotoxy(pos + 2, 0);
  153. lcd_puts(" ");
  154. lcd_gotoxy(pos + 2, 1);
  155. lcd_putc((uint8_t)0);
  156. }
  157.  
  158. void deux(int pos)
  159. {
  160. lcd_gotoxy(pos, 0);
  161. lcd_putc((uint8_t)1);
  162. lcd_gotoxy(pos, 1);
  163. lcd_putc((uint8_t)2);
  164. lcd_gotoxy(pos + 1, 0);
  165. lcd_putc((uint8_t)5);
  166. lcd_gotoxy(pos + 1, 1);
  167. lcd_putc((uint8_t)0);
  168. lcd_gotoxy(pos + 2, 0);
  169. lcd_putc((uint8_t)2);
  170. lcd_gotoxy(pos + 2, 1);
  171. lcd_putc((uint8_t)0);
  172. }
  173.  
  174. void trois(int pos)
  175. {
  176. lcd_gotoxy(pos, 0);
  177. lcd_putc((uint8_t)1);
  178. lcd_gotoxy(pos, 1);
  179. lcd_putc((uint8_t)0);
  180. lcd_gotoxy(pos + 1, 0);
  181. lcd_putc((uint8_t)5);
  182. lcd_gotoxy(pos + 1, 1);
  183. lcd_putc((uint8_t)0);
  184. lcd_gotoxy(pos + 2, 0);
  185. lcd_putc((uint8_t)2);
  186. lcd_gotoxy(pos + 2, 1);
  187. lcd_putc((uint8_t)2);
  188. }
  189.  
  190. void quatre(int pos)
  191. {
  192. lcd_gotoxy(pos, 0);
  193. lcd_putc((uint8_t)2);
  194. lcd_gotoxy(pos, 1);
  195. lcd_puts(" ");
  196. lcd_gotoxy(pos + 1, 0);
  197. lcd_putc((uint8_t)0);
  198. lcd_gotoxy(pos + 1, 1);
  199. lcd_puts(" ");
  200. lcd_gotoxy(pos + 2, 0);
  201. lcd_putc((uint8_t)2);
  202. lcd_gotoxy(pos + 2, 1);
  203. lcd_putc((uint8_t)2);
  204. }
  205.  
  206. void cinq(int pos)
  207. {
  208. lcd_gotoxy(pos, 0);
  209. lcd_putc((uint8_t)2);
  210. lcd_gotoxy(pos, 1);
  211. lcd_putc((uint8_t)0);
  212. lcd_gotoxy(pos + 1, 0);
  213. lcd_putc((uint8_t)5);
  214. lcd_gotoxy(pos + 1, 1);
  215. lcd_putc((uint8_t)0);
  216. lcd_gotoxy(pos + 2, 0);
  217. lcd_putc((uint8_t)1);
  218. lcd_gotoxy(pos + 2, 1);
  219. lcd_putc((uint8_t)2);
  220. }
  221.  
  222. void six(int pos)
  223. {
  224. lcd_gotoxy(pos, 0);
  225. lcd_putc((uint8_t)2);
  226. lcd_gotoxy(pos, 1);
  227. lcd_putc((uint8_t)2);
  228. lcd_gotoxy(pos + 1, 0);
  229. lcd_putc((uint8_t)5);
  230. lcd_gotoxy(pos + 1, 1);
  231. lcd_putc((uint8_t)0);
  232. lcd_gotoxy(pos + 2, 0);
  233. lcd_putc((uint8_t)1);
  234. lcd_gotoxy(pos + 2, 1);
  235. lcd_putc((uint8_t)2);
  236. }
  237.  
  238. void sept(int pos)
  239. {
  240. lcd_gotoxy(pos, 0);
  241. lcd_putc((uint8_t)1);
  242. lcd_gotoxy(pos, 1);
  243. lcd_puts(" ");
  244. lcd_gotoxy(pos + 1, 0);
  245. lcd_putc((uint8_t)1);
  246. lcd_gotoxy(pos + 1, 1);
  247. lcd_puts(" ");
  248. lcd_gotoxy(pos + 2, 0);
  249. lcd_putc((uint8_t)2);
  250. lcd_gotoxy(pos + 2, 1);
  251. lcd_putc((uint8_t)2);
  252. }
  253.  
  254. void huit(int pos)
  255. {
  256. lcd_gotoxy(pos, 0);
  257. lcd_putc((uint8_t)2);
  258. lcd_gotoxy(pos, 1);
  259. lcd_putc((uint8_t)2);
  260. lcd_gotoxy(pos + 1, 0);
  261. lcd_putc((uint8_t)5);
  262. lcd_gotoxy(pos + 1, 1);
  263. lcd_putc((uint8_t)0);
  264. lcd_gotoxy(pos + 2, 0);
  265. lcd_putc((uint8_t)2);
  266. lcd_gotoxy(pos + 2, 1);
  267. lcd_putc((uint8_t)2);
  268. }
  269.  
  270. void neuf(int pos)
  271. {
  272. lcd_gotoxy(pos, 0);
  273. lcd_putc((uint8_t)2);
  274. lcd_gotoxy(pos, 1);
  275. lcd_putc((uint8_t)0);
  276. lcd_gotoxy(pos + 1, 0);
  277. lcd_putc((uint8_t)5);
  278. lcd_gotoxy(pos + 1, 1);
  279. lcd_putc((uint8_t)0);
  280. lcd_gotoxy(pos + 2, 0);
  281. lcd_putc((uint8_t)2);
  282. lcd_gotoxy(pos + 2, 1);
  283. lcd_putc((uint8_t)2);
  284. }
  285.  
  286.  
  287.  
  288. void lcd_affi_Gros_Chiffre(int x, int pos)
  289. {
  290. switch (x)
  291. {
  292. case 0 : zero(pos); break;
  293. case 1 : un(pos); break;
  294. case 2 : deux(pos); break;
  295. case 3 : trois(pos); break;
  296. case 4 : quatre(pos); break;
  297. case 5 : cinq(pos); break;
  298. case 6 : six(pos); break;
  299. case 7 : sept(pos); break;
  300. case 8 : huit(pos); break;
  301. case 9 : neuf(pos); break;
  302. }
  303. }
  304.  
  305. void lcd_efface_Gros_Chiffre(int pos)
  306. {
  307. lcd_gotoxy(pos, 0); lcd_puts(" ");
  308. lcd_gotoxy(pos, 1); lcd_puts(" ");
  309. lcd_gotoxy(pos + 1, 0); lcd_puts(" ");
  310. lcd_gotoxy(pos + 1, 1); lcd_puts(" ");
  311. lcd_gotoxy(pos + 2, 0); lcd_puts(" ");
  312. lcd_gotoxy(pos + 2, 1); lcd_puts(" ");
  313. }
  314.  

5 Le circuit imprimé

Ce circuit imprimé conçu pour se plaquer sous l'afficheur LCD ce qui facilite l’insertion dans un petit boîtier.

6 Flashage et gravage du circuit :

13 avr 2016:
...cinq mois que j'avais mis cette réalisation de côté pour cause de choses plus urgentes à faire. Mais comme j'aime bien finir ce que j'ai commencé, voici la suite...
J'ai flashé le circuit avec ma machine laser décrite ICI .
Tout fonctionne correctement, après une petite correction ( le footprint que j'avais créé pour le module NNEO-6M (ou 7M) avait les pins TX et RX permutés. J'ai corrigé le footprint et le dessin kicad visible au #5, mais le circuit imprimé était déjà réalisé. Donc cela explique la petite différence entre le dessin et le circuit gravé au niveau des piste du haut).

7 L'horloge dans son boîtier

Le bouton poussoir fait basculer entre les deux modes d'affichage.

8 Second mode d'affichage :

9 Coup d'oeil dans la boite :

L'alimentation 5V dc est constituée par un petit "adaptateur 5V - 0.5A" qui se branche directement sur la prise secteur 230V.

10 Vue par la tranche

Il se trouve que l'écartement des trous de fixation du module GPS NEO-6M est exactement le même que celui des trous latéraux de l'afficheur LCD. Ce qui permet de fixer l'un à l'autre très simplement par deux vis + entretoises.

11 Documents

12 -

Liens...

19142