Programmation des AVR en C
sous LINUX
avec Kontrollerlab

Attention:

Le programme Kontrollerlab qui était un IDE parfaitement adapté à la programmation des uC ATMEL AVR était lui même développé sous KDE3.5
Or KDE3.5 a laissé la place à KDE4 (dans les dernières versions de Linux Ubuntu) et la cohabitation KDE3-KDE4 est délicate et déconseillée. Le portage de Kontrollerlab sur KDE4, bien qu'entrevu en 2008, n'est toujours pas réalisé à ma connaissance.
C'est la raison pour laquelle j'ai abandonné Kontrollerlab au profit de Geany, qui correctement paramétré, permet d'obtenir le même résultat.


1 Installation du compilateur avr-gcc :

Tout d'abord il faut installer avr-gcc qui est un compilateur libre multi-plateformes C pour AVR

Voici plus précisément les paquets que j'ai installés, concernant "avr"




Vous pouvez des lors écrire le programme source (par exemple essai1.c) dans un éditeur de texte puis le compiler avec avr-gcc en ligne de commande (le lancer dans un terminal, en ayant soin de configurer au préalable un fichier Makefile (fichier texte définissant les options de compilation) qu'on place dans le répertoire du fichier essai1.c)
C'est peu commode? Sous Windows on avait des outils graphiques pour programmer? Bonne nouvelle, sous Linux aussi! On peut utiliser le pack winAVR (malheureusement disponible uniquement pour Windows à ma connaissance) en l'installant sous linux avec wine. C'est un logiciel sous licence GNU. Oui mais wine... on peut ne pas l'apprécier... philosophiquement... Et puis en cas d'erreurs de compilation, le fait de tourner sous wine peut éventuellement compliquer les choses.

Ok, j'ai trouvé mieux, une interface graphique, open source, purement Linux: KontrollerLab, propose par cadManic.org.
Nécessite également d'installer les paquets avr listés ci-dessus, plus le paquet avrdude afin de programmer directement l'ATmega depuis kontrollerlab.

et pour la dernière version 0.8.0-beta1:

Bon d'accord c'est en anglais, ce n'est pas un problème n'est-ce pas?

2 Logiciel libre

Je lis sur le site cadManiac:

"cadManiac.org is a non-commercial, non-profit site for open source development of mostly Linux(c) based software for electronics development. Everything on this site, including software, information, pictures, texts, or files of any kind, are published under the terms of the GNU GPL License and the GNU Free Documentation License"

Vive le logiciel libre! Grâce à de telles initiatives je vais bientôt pouvoir me passer TOTALEMENT de Windows.

25 avril 2012:

C'est fait depuis plus de trois ans! (depuis Ubuntu 9.04 et suivants) Je fais actuellement TOUT sous Linux, y compris le développement de ce site en PHP5, CSS, javascript, jquery...

3 KontrollerLab

KontrollerLab permet de:
  • écrire le programme source en C.
  • configurer (avec un " wizard") un fichier de configuration (fichier.h) pour piloter un afficheur LCD et le place automatiquement dans le répertoire du source.
  • compiler et lier le source pour obtenir un fichier objet .hex (pour un usage éventuel par un soft programmeur externe)
  • d'appeler automatiquement (avec un bouton) le programme UISP ou AVRDUDE et de programmer l'ATmega in-situ (si le paquet avrdude est installé sur le système, et kontrolleurlab lancé avec droits administrateur)
  • de débugger

4 Exemple de programme

Voici un tout petit programme qui fait plein de choses;

C'est la version en langage C de mon soft en Pascal destiné à mon générateur VHF 160MHz décrit sur ce site (avec schémas plus complets).

Il s'y trouve bien des choses réutilisables:
  • gestion des ports
  • piloter un afficheur LCD réparti sur 2 ports
  • afficher un texte
  • afficher un nombre entier en représentation décimale (sur le LCD)
  • afficher un nombre (sur le LCD) en représentation binaire
  • gestion de leds
  • scrutation de boutons
  • utilisation du convertisseur analogique/numerique de l'ATmega8
  • gestion de la synthèse d'un signal PWM (pulse width modulation = modulation de largeur d'impulsions, c.a.d signal rectangulaire à rapport cyclique variable, commandé - il est fait sans consommer de temps processeur, pas d'interruptions).
Voici les fichiers correspondants: Soft_en_C.tar.gz

CODE SOURCE en langage C
  1. /*==============================================================================
  2. =
  3. par Silicium628
  4. versions: voir plus bas dans la partie "const" - derniere mise à jour 15 avril 2009
  5. ================================================================================
  6. Notes de versions:
  7. la version 3.1 en Pascal depassait en taille les 8 ko max de l'ATmega8 si compilee en mode normal
  8. ET la compilation en mode 'make and optimise' semble boguee: il se produit des erreurs a l'execution
  9. ================================================================================
  10. Pilotage de la PLL integree LM7001 en mode FM, pas = 100, 50, et 25kHz
  11. -Fréquences synthétisées 96 à 160 MHz avec la même self dans le VCO
  12. -Affichage LCD 2 x 20 caractères ("splitté entre deux ports de l'ATmega)
  13. -Sélections rapide des fréquences par bouton rotatif ('en continu')
  14. -pas de synthese sélectionnable = 100, 50, et 25kHz
  15. -sauts en frequences de 10MHz, 1MHz, 100kHz, 50kHz et 25kHzpar rotation du
  16. bouton pas-a-pas
  17.  
  18.   F_kHz := Facteur_N * PAS; (Facteur_N est le coeficient de division de la frequence envoyé à la PLL)
  19.  
  20. on definit 5 modes de fonctionnement du bouton rotatif (variable 'mode' et numero de la LED allumee)
  21. à chaque mode correspond une longueur de saut de la frequence de sortie ainsi qu'un PAS de synthese suivant le tableau suivant:
  22.  
  23. MODE SAUT PAS
  24. 1 25kHz 25kHz
  25. 2 50kHz 50kHz
  26. 3 100kHz 100kHz
  27. 4 1MHz 100kHz
  28. 5 10MHz 100kHz
  29.  
  30. La diode varicap du VCO est alimenté par la combinaison de deux tensions:
  31. -un première tension genérée classiquement par le comparateur de phase de la PLL apres filtre passe-bas
  32. -une seconde tension generée par l'ATmega (par integration d'un signal PWM [modulation à largeur d'impultion])
  33. afin de centrer en permanence la fenêtre de capture de la PLL sur la fréquence désirée, ce aui permet
  34. d'étendre considérablement la plage de fréquences couvertes.
  35.  
  36. ================================================================================
  37. */
  38. // #include <math.h>
  39.  
  40.  
  41. #define F_CPU 16000000
  42.  
  43. #include <avr/io.h>
  44. #include <util/delay.h>
  45.  
  46. #include "dm_lcd.c"
  47.  
  48.  
  49.  
  50. #define bouton_UP 0b00000100
  51. #define bouton_DOWN 0b00001000
  52. #define RAZ_4017 0b00000001
  53. #define clk_4017 0b00000010
  54.  
  55. char * version = "1.4";
  56.  
  57. int mode; // = 1..5 pointeur vers longueur de sauts et numero de la LED à allumer.
  58. int PAS; // 10M, 1M, 25, 50, 100 kHz ; longueur des sauts effectues avec le bouton rotatif
  59. unsigned long int facteur_N; // facteur de division à envoyer à la PLL dans le registre "Programmable divider"
  60. unsigned long int F_kHz;
  61. int memo_pos_rot;
  62. int pos_rot;
  63. unsigned long int data; //D0..D13 + T0..1 Note: D0=LSB
  64. unsigned int commande; //B0..B2 + TB + R0..2 + S Note: B0=LSB , S=MSB
  65.  
  66. void init_ports (void) // ports perso
  67. // 0 = entree, 1=sortie ; les 1 sur les pins en entrees activent les R de Pull Up (tirage à VCC)
  68. {
  69. PORTB = 0b00000000;
  70. DDRB |= 0b00001000; // portB[3] = sortie (OC2)
  71.  
  72. DDRC &= 0b001111; //PC4 en entree (IR) PC5 en entree (ADC5)
  73.  
  74. DDRD = 0b11110011;
  75. PORTD = 0b00001100; // active R de pullup sur PD2 et PD3 en entrées
  76. }
  77.  
  78.  
  79. void InitADC (void)
  80. {
  81. ADCSRA = _BV(ADEN) | _BV(ADPS2); // Activate ADC with Prescaler 16 --> 1Mhz/16 = 62.5kHz
  82. ADMUX = 5; // Select pin ADC5 using MUX
  83. }
  84.  
  85.  
  86. void InitINTs (void)
  87. /*
  88.  TCCR2:
  89. wgm21,20 =11 ->Fast PMW
  90.  
  91. com21,com20=01 ->Set OC2 on Compare Match, clear OC2 at TOP (valable pour le mode Fast PWM); voir p:116
  92.  
  93. bits2,1,0: prescaler (010 = 1/8)
  94.  
  95. */
  96. {
  97. // div
  98.  
  99. TCCR2= 0b01111010; // Timer2 utilisé. mode Fast PWM (WGM21,20 = 11); OC2 = sortie PWM voir p:115
  100. TIMSK |= 0b00000000; // INT Timer2 comp disable; INT Timer2 overflow disable;
  101. GICR |= 0b00000000; // gere les INTs voir page 67 du pdf
  102. MCUCR |= 0b00000010; // The falling edge of INT0 generates an interrupt request. p:67 du pdf
  103.  
  104. }
  105.  
  106.  
  107. void lcd_gotoxy_clrEOL (int x, int y)
  108. // place le curseur en x,y et efface jusqu'a la fin de la ligne
  109. {
  110. lcd_gotoxy(x, y);
  111. int i;
  112. for (i=x; i<20; i++)
  113. { lcd_puts(" "); }
  114. lcd_gotoxy(x, y);
  115. }
  116.  
  117.  
  118. void lcd_aff_nb (unsigned long int valeur, int nb_chiffres, int nb_decimales )
  119. //affiche un nombre en representation decimale
  120. // 266 octets
  121. {
  122. unsigned char r ;
  123. char tbl[7];
  124. unsigned i;
  125.  
  126. for (i=1; i<=nb_chiffres; i++)
  127. {
  128. r=48 + valeur % 10; // modulo (reste de la division)
  129. valeur /= 10; // quotient
  130. tbl[i]=r;
  131. };
  132. for (i=1; i<=nb_chiffres; i++)
  133. {
  134. if (i== (nb_chiffres - nb_decimales +1) ) { lcd_puts("."); }
  135. lcd_putc(tbl[nb_chiffres +1 -i]);
  136. }
  137.  
  138. }
  139.  
  140.  
  141. void lcd_aff_bin (unsigned long int valeur, int nb_digits)
  142. //affiche un nombre en representation binaire
  143. // 16 bits max
  144. {
  145. unsigned char r ;
  146. char tbl[17];
  147. unsigned i;
  148.  
  149. for (i=1; i<=nb_digits; i++)
  150. {
  151. r= 48 + valeur % 2; // modulo (reste de la division)
  152. valeur /= 2; // quotient
  153. tbl[i]=r;
  154. };
  155.  
  156. for (i=1; i<=nb_digits; i++)
  157. {
  158. lcd_putc(tbl[nb_digits +1 -i]);
  159. }
  160. }
  161.  
  162.  
  163.  
  164. void calcul_PAS(void)
  165. {
  166. switch (mode)
  167. {
  168. case (1): PAS= 25 ;
  169. break;
  170. case (2): PAS= 50;
  171. break;
  172. default: PAS= 100;
  173. break;
  174. }
  175. }
  176.  
  177.  
  178. void init_variables(void)
  179. {
  180. mode= 3;
  181. calcul_PAS();
  182. facteur_N= 1440; // pour F_out = 100 * 1440 = 144000 kHz = 144 MHz
  183. }
  184.  
  185.  
  186. void clk_PLL(void) // sur pin CL
  187. {
  188. _delay_us(10);
  189. PORTD |= 0b01000000;
  190. _delay_us(10);
  191. PORTD &= 0b10111111;
  192. _delay_us(10);
  193. }
  194.  
  195.  
  196. void out_PLL(void) // 24 bits vers LM7001; voir datasheet LM7001
  197.  
  198. {
  199. int n;
  200. //calcul du mot de commande
  201. // ligne ci-dessous = config pour pas=10kHz avec Qz=7.2MHz
  202. // ATTENTION: sur le datasheet, les mots binaires sont tous écrit avec le LSB à GAUCHE. Merci Sanyo!
  203. // octet de commande = S,R2,R1,R0,TB,B2,B1,B0 (écrit à l'endroit, LSB à DROITE)
  204.  
  205. switch (PAS)
  206. {
  207. case (10) : commande = 0b10010000; //S=1 (FM-IN); R2..0=001 ; TB,B2,B1,B0,TB=0 (diviseur de la ref fixé par R2..0)
  208. break;
  209. case (25) : commande = 0b10100000; //S=1 (FM-IN); R2..0=010 ; TB,B2,B1,B0,TB=0 (diviseur de la ref fixé par R2..0)
  210. break;
  211. case (50) : commande = 0b11000000; //S=1 (FM-IN); R2..0=100 ; TB,B2,B1,B0,TB=0 (diviseur de la ref fixé par R2..0)
  212. break;
  213. case (100) : commande = 0b10000000; //S=1 (FM-IN); R2..0=000 ; TB,B2,B1,B0,TB=0 (diviseur de la ref fixé par R2..0)
  214. break;
  215. default: {}
  216. }
  217.  
  218. //envoi de la frequence
  219.  
  220. PORTD &= 0b10111111; // CL = 0
  221. // active_CE; (pin CE du LM7001)
  222. PORTD |= 0b00100000; // ENB=1 (active le transfert entre le uC et le MC145170)
  223.  
  224. unsigned long int masque;
  225.  
  226. for (n=0; n<= 13; n++) // on sort le LSB en premier
  227. {
  228. masque = (1 << n); // masque = 00000000000001 .. 10000000000000 le '1' se deplacant de droite a gauche, 14 bits en tout
  229. // if bit(facteur_N, n)
  230. if ( (facteur_N & masque) != 0) PORTD |= 0b10000000;
  231. else PORTD &= 0b01111111;
  232.  
  233. clk_PLL();
  234. }
  235.  
  236. PORTD &= 0b01111111; // T0 (toujours =0)
  237. clk_PLL();
  238.  
  239. PORTD &= 0b01111111; // T1 (toujours =0)
  240. clk_PLL();
  241.  
  242. // envoi de la commande
  243.  
  244. for (n=0; n<=7; n++) // on sort le LSB = B0 en premier et le MSB (S) en dernier.
  245. {
  246. // ATTENTION: sur le datasheet, les mots binaires sont tous écrit avec le LSB à GAUCHE. Merci Sanyo!
  247. masque = (1 << n);
  248. // if bit(commande, n)
  249. if (commande & masque) PORTD |= 0b10000000;
  250. else PORTD &= 0b01111111;
  251.  
  252. clk_PLL();
  253. }
  254.  
  255. // desactive_CE;
  256. PORTD &= 0b11011111; // ENB=0 (desactive ENB/ ce qui effectue le transfert dans les registres internes)
  257. }
  258.  
  259.  
  260.  
  261. void calcul_Frequence(void)
  262. {
  263. F_kHz=facteur_N * PAS;
  264. }
  265.  
  266.  
  267. void affiche_facteur_N (void)
  268. {
  269. lcd_gotoxy_clrEOL(0, 3);
  270. lcd_aff_nb(facteur_N, 4, 0);
  271. }
  272.  
  273.  
  274. void affiche_frequence(void)
  275. {
  276. calcul_Frequence();
  277. lcd_gotoxy_clrEOL (4, 0);
  278. lcd_aff_nb(F_kHz ,6, 3);
  279. lcd_puts("MHz");
  280. }
  281.  
  282.  
  283. void Affiche_OCR2(void)
  284. {
  285. lcd_gotoxy_clrEOL (6, 3);
  286. lcd_puts("OCR2= ");
  287. lcd_aff_nb(OCR2, 3, 0);
  288. }
  289.  
  290. void affiche_mode(void)
  291. {
  292. lcd_gotoxy(8, 1);
  293.  
  294. switch (mode)
  295. {
  296. case (1) : lcd_puts("25 kHz ");
  297. break;
  298.  
  299. case (2) : lcd_puts("50 kHz ");
  300. break;
  301.  
  302. case (3): lcd_puts("100 kHz");
  303. break;
  304.  
  305. case (4) : lcd_puts("1 MHz ");
  306. break;
  307.  
  308. case (5) : lcd_puts("10 MHz ");
  309. break;
  310.  
  311. default: {}
  312. }
  313.  
  314. // LCDclrEOL;
  315. lcd_gotoxy(11, 2);
  316. // LCDclrEOL;
  317. lcd_aff_nb(PAS ,3, 0);
  318. lcd_puts("kHz");
  319. }
  320.  
  321.  
  322. void out_PWM(void)
  323. //le signal PWM sorti sur le pin OC2 est convertit en une tension continue (0..24V)
  324. //qui permet de centrer la fenetre de capture de la PLL (VCO + LM7001) sur la frequence desirée
  325. //La valeur est obtenue par la formule analytique OCR2 = 2*( F - 60 ) obtenue empiriquement
  326. // voir la courbe F-f(OCR2) sur feuille de calcul Open Office jointe
  327.  
  328. {
  329. int v1;
  330.  
  331. //cette partie commentee consomme 3000 octets! donc on evite!
  332. // (en particulier la multiplication de deux float)
  333. //je les remplace par une approche discrete qui consomme moin de 200 octets
  334. // float a;
  335. // float b;
  336. // a= F_kHz / 1000;
  337. // b= (a - 80) / 20;
  338. // OCR2_real = b * b;
  339. // // if (OCR2_real > 255) {OCR2_real= 255;}
  340. // // // OCR2= floor(OCR2_real);
  341.  
  342. calcul_Frequence();
  343. v1=5;
  344. if (F_kHz > 95000) { v1= 11; }
  345. if (F_kHz > 100000) { v1= 20; }
  346. if (F_kHz > 105000) { v1= 31; }
  347. if (F_kHz > 110000) { v1= 40; }
  348. if (F_kHz > 115000) { v1= 58; }
  349. if (F_kHz > 120000) { v1= 80; }
  350. if (F_kHz > 125000) { v1= 101; }
  351. if (F_kHz > 130000) { v1= 125; }
  352. if (F_kHz > 133000) { v1= 140; }
  353. if (F_kHz > 135000) { v1= 151; }
  354. if (F_kHz > 137000) { v1= 162; }
  355. if (F_kHz > 140000) { v1= 180; }
  356. if (F_kHz > 143000) { v1= 198; }
  357. if (F_kHz > 145000) { v1= 211; }
  358. if (F_kHz > 150000) { v1= 245; }
  359. OCR2=v1;
  360. Affiche_OCR2();
  361. }
  362.  
  363.  
  364. void eteint_toutes_LED (void)
  365. {
  366. PORTD |= RAZ_4017;
  367. _delay_us(10);
  368. PORTD &= ~RAZ_4017;
  369. _delay_us(10);
  370. }
  371.  
  372. void allume_LED (int num)
  373. {
  374. int n;
  375. eteint_toutes_LED();
  376. num++;
  377. for(n=1; n<num; n++)
  378. {
  379. PORTD |= clk_4017;
  380. _delay_us(1);
  381. PORTD &= ~clk_4017;
  382. _delay_us(1);
  383. }
  384. }
  385.  
  386.  
  387. void incremente_PAS(void)
  388. {
  389. switch (PAS)
  390. {
  391. case (25) :
  392. PAS= 50;
  393. facteur_N /= 2;
  394. break;
  395.  
  396. case (50) :
  397. PAS= 100;
  398. facteur_N /= 2;
  399. break;
  400. }
  401. // Affiche_mode;
  402.  
  403. affiche_frequence();
  404. affiche_facteur_N();
  405. out_PLL();
  406. out_PWM();
  407. }
  408.  
  409.  
  410. void decremente_PAS(void)
  411. {
  412. switch (PAS)
  413. {
  414. case (100) :
  415. PAS= 50;
  416. facteur_N *= 2;
  417. break;
  418.  
  419. case (50) :
  420. PAS= 25;
  421. facteur_N *= 2;
  422. break;
  423. }
  424. // Affiche_mode;
  425.  
  426. affiche_frequence();
  427. affiche_facteur_N();
  428. out_PLL();
  429. out_PWM();
  430. }
  431.  
  432.  
  433.  
  434. void incremente_N (void)
  435. // fonction appelee lorsqu'on tourne le selecteur rotatif
  436. {
  437. switch (mode)
  438. {
  439. case(4) :
  440. facteur_N= facteur_N + 10;
  441. if (facteur_N > 1600) { facteur_N= 1600; }
  442. break;
  443. case(5) :
  444. facteur_N= facteur_N + 100;
  445. if (facteur_N > 1600) { facteur_N= 1600; }
  446. break;
  447.  
  448. default:
  449. if (F_kHz < 160000) {facteur_N= facteur_N + 1;}
  450. }
  451. affiche_frequence();
  452. affiche_facteur_N();
  453. out_PLL();
  454. out_PWM();
  455. }
  456.  
  457.  
  458. void decremente_N (void)
  459. // fonction appelee lorsqu'on tourne le selecteur rotatif
  460. {
  461. switch (mode)
  462. {
  463. case(4) :
  464. facteur_N= facteur_N - 10;
  465. if (facteur_N < 900) {facteur_N= 900;}
  466. break;
  467.  
  468. case(5) :
  469. facteur_N= facteur_N - 100;
  470. if (facteur_N < 900) { facteur_N= 900;}
  471. break;
  472. default:
  473. if (F_kHz > 90000) { facteur_N= facteur_N - 1; }
  474. }
  475. affiche_frequence();
  476. affiche_facteur_N();
  477.  
  478. out_PLL();
  479. out_PWM();
  480.  
  481. }
  482.  
  483.  
  484. void scrute_boutons(void)
  485. // 336 octets
  486. // deux boutons poussoirs permettent de changer la longueur des sauts en frequences (que j'ai appelé "mode")
  487. // met le mode à jour
  488. // le tableau presente en preambule montre que le PAS doit changer entre les modes 1 et 2 ainsi que 2 et 3
  489. {
  490. int n=0;
  491.  
  492. if ( (PIND & 0b00000100) == 0) {
  493. switch (mode)
  494. {
  495. case(1) :
  496. {
  497. mode= 2;
  498. allume_LED(mode);
  499. incremente_PAS(); // recalcule facteur_N en fonction du nouveau PAS
  500. affiche_mode();
  501. _delay_ms(200);
  502. n++;
  503. //while (((PIND & 0b00000100 ) != 0) | (n < 10) ) {}
  504. }
  505. break;
  506.  
  507. case(2) :
  508. {
  509. mode= 3;
  510. allume_LED(mode);
  511. incremente_PAS(); // recalcule facteur_N en fonction du nouveau PAS
  512. affiche_mode();
  513. _delay_ms(200);
  514. n++;
  515. //while (((PIND & 0b00000100 ) != 0) | (n < 10) ) {}
  516. }
  517. break;
  518.  
  519. case(3) :
  520. case(4) :
  521. {
  522. mode++;
  523. allume_LED(mode);
  524. affiche_mode();
  525. _delay_ms(200);
  526. }
  527.  
  528. default: {}
  529. }
  530.  
  531. lcd_gotoxy(0, 1);
  532. // lcd_puts (string(mode));
  533. } else {} ;
  534.  
  535. if ( (PIND & 0b00001000) == 0) {
  536. switch (mode) {
  537. case(2) :
  538. {
  539. mode= 1;
  540. allume_LED(mode);
  541. decremente_PAS(); // recalcule facteur_N en fonction du nouveau PAS
  542. affiche_mode();
  543. _delay_ms(200);
  544. n++;
  545. // while (((PIND & 0b00001000 ) != 0) | (n < 10) ) {}
  546. }
  547. break;
  548.  
  549. case(3) :
  550. {
  551. mode= 2;
  552. allume_LED(mode);
  553. decremente_PAS(); // recalcule facteur_N en fonction du nouveau PAS
  554. affiche_mode();
  555. _delay_ms(200);
  556. n++;
  557. // while (((PIND & 0b00001000 ) != 0) | (n < 10) ) {}
  558. }
  559. break;
  560.  
  561. case(4):
  562. case(5):
  563. {
  564. mode--;
  565. allume_LED(mode);
  566. affiche_mode();
  567. _delay_ms(200);
  568. n++;
  569. // while (((PIND & 0b00001000 ) != 0) | (n < 10) ) {}
  570. }
  571. break;
  572.  
  573. default: {}
  574. }
  575. } else { }
  576.  
  577. if (mode <1) mode= 1; else {};
  578. if (mode >5) mode=5; else {};
  579. // allume_LED(mode);
  580. }
  581.  
  582.  
  583. void acqui_pos_rot (void)
  584. // lit la position d'un potentiometre à resistances CMS discretes (63k au total)
  585.  
  586. {
  587. unsigned long int acqui_ADC_rot;
  588.  
  589. ADCSRA |= _BV(ADSC); //Start conversion - resolution 10bits
  590.  
  591.  
  592. while (ADCSRA & _BV(ADSC) ) {} // attend la fin de la converstion
  593.  
  594. acqui_ADC_rot = ADCW; // lit la value convertie
  595.  
  596. pos_rot= 19;
  597. //la structure suivante en "if then" est moins gourmande en memoire qu'un case of.
  598.  
  599. if (acqui_ADC_rot > 200) { pos_rot= 18; }
  600. if (acqui_ADC_rot > 300) { pos_rot= 17; }
  601. if (acqui_ADC_rot > 450) { pos_rot= 16; }
  602. if (acqui_ADC_rot > 550) { pos_rot= 15; }
  603. if (acqui_ADC_rot > 630) { pos_rot= 14; }
  604. if (acqui_ADC_rot > 670) { pos_rot= 13; }
  605. if (acqui_ADC_rot > 700) { pos_rot= 12; }
  606. if (acqui_ADC_rot > 735) { pos_rot= 11; }
  607. if (acqui_ADC_rot > 755) { pos_rot= 10; }
  608. if (acqui_ADC_rot > 775) { pos_rot= 9; }
  609. if (acqui_ADC_rot > 790) { pos_rot= 8; }
  610. if (acqui_ADC_rot > 810) { pos_rot= 7; }
  611. if (acqui_ADC_rot > 825) { pos_rot= 6; }
  612. if (acqui_ADC_rot > 838) { pos_rot= 5; }
  613. if (acqui_ADC_rot > 850) { pos_rot= 4; }
  614. if (acqui_ADC_rot > 859) { pos_rot= 3; }
  615. if (acqui_ADC_rot > 868) { pos_rot= 2; }
  616. if (acqui_ADC_rot > 874) { pos_rot= 1; }
  617. if (acqui_ADC_rot > 880) { pos_rot= 0; }
  618.  
  619. // LCDxy(10, 3);
  620. // LCDclrEOL;
  621. // Write(LCDout, ByteToStr(pos_rot : 3));
  622.  
  623. }
  624.  
  625.  
  626.  
  627. int main (void)
  628. {
  629. init_variables();
  630. init_ports();
  631. InitADC();
  632. allume_LED(mode);
  633. InitINTs();
  634. out_PLL();
  635.  
  636.  
  637. lcd_init(LCD_DISP_ON);
  638. lcd_clrscr();
  639. lcd_home();
  640. // lcd_puts("APE2008 version ");
  641. lcd_puts(version);
  642. _delay_ms(1000);
  643.  
  644. lcd_gotoxy (0, 0);
  645. lcd_puts("Out ");
  646.  
  647. lcd_gotoxy (0, 1);
  648. lcd_puts("SAUTS:");
  649. lcd_gotoxy (0, 2);
  650. lcd_puts("pas synth");
  651.  
  652. lcd_gotoxy (8, 3);
  653.  
  654. affiche_frequence();
  655. affiche_mode();
  656.  
  657. //unsigned long int masque_de_test;
  658. //int n1;
  659.  
  660. while(1)
  661. {
  662. scrute_boutons();
  663.  
  664. memo_pos_rot= pos_rot;
  665. acqui_pos_rot();
  666.  
  667. int suite =1; // utilise comme boolean. ah ce C peu type!
  668. // oui bon l'instruction if du C est invraissemblablement confuse pour quelqu'un qui connait le Pascal !
  669. // (en particulier les variantes avec if elsif endif)
  670. // d'ou l'utilisation de ce drapeau. C'est moins pire que des goto quand meme!
  671.  
  672.  
  673. if (pos_rot != memo_pos_rot) // si le selecteur a bouge
  674. {
  675. //quand le selecteur rotatif passe de 19 a 0, il faut continuer a incrementer et vice-versa
  676. if ( (memo_pos_rot == 0) & (pos_rot == 19) ) { decremente_N(); suite =0; }
  677. if ( (memo_pos_rot == 19) & (pos_rot == 0) ) { incremente_N(); suite =0; }
  678. //le reste du temps l'incrementation va dans le sens des valeurs croissantes
  679. if (suite)
  680. {
  681. if (pos_rot > memo_pos_rot) { incremente_N(); }
  682. if (pos_rot < memo_pos_rot) {decremente_N(); }
  683. }
  684. }
  685.  
  686. _delay_ms(100);
  687.  
  688. //=============== pour TEST =================
  689. // for (n1=0; n1<= 13; n1++) // on sort le LSB en premier
  690. // {
  691. // masque_de_test = (1 << n1);
  692. //
  693. // lcd_gotoxy_clrEOL (0, 1);
  694. // lcd_aff_bin(facteur_N,16);
  695. //
  696. // lcd_gotoxy_clrEOL (0, 2);
  697. // lcd_aff_bin(masque_de_test,16);
  698. //
  699. // lcd_gotoxy_clrEOL (0, 3);
  700. // lcd_aff_bin(facteur_N & masque_de_test,16);
  701. //
  702. // lcd_gotoxy (19, 3);
  703. //
  704. // if (facteur_N & masque_de_test) // != 0)
  705. // lcd_puts("i");
  706. // else
  707. // lcd_puts(" ");
  708. //
  709. // _delay_ms(1000);
  710. // }
  711. //=======================================
  712.  
  713. }
  714. }
  715.  
  716.  
C'est la confirmation que la compilation fonctionne ainsi que la programmation in-situ (ISP) de l'ATmega, le tout en 2 clics (voire même un seul, avec la petite fusée!), sans quitter le logiciel KontrollerLab!
Copie d'écran de KontrollerLab
(8.0.0 beta1 tournant sous Ubuntu 8.04)
(cliquer pour zoom)




5 Quelques astuces pour Kontrollerlab?

Quelques astuces pour Kontrollerlab?

Si AVRDUDE renvoit un message d'erreur signifiant que vous n'avez pas la permission d'accéder au composant USB, il faut lancer KontrollerLab avec des droits administrateurs (par la commande gksudo kontrollerlab). J'avais le même problème avec Avr-burnO-mat, et donner des droits en lecture-écriture au device /dev/usb.. ne résolvait pas le problème. Je suis conscient que lancer un programme avec les droits administrateur n'est jamais une bonne idée, il reste à trouver une meilleure solution...

J'ai trouvé sur le Net (ici) une solution pour éviter de devoir lancer kontrollerlab (et avrdude) en mode administrateur. La voici:

(je cite:)

Pour ne pas être embêté par le fait de passer en su, voici la méthode suivie tirée du site
http://forums.obdev.at/viewtopic.php?p=4436
How to add user permission for USBasp (I have tested this method in ubuntu 7.10):
source:http://www.bitpim.org/help/
1. Create new rule for udev
Code:

sudo gedit /etc/udev/rules.d/60-objdev.rules

2. Edit new rule in gedit and add following:
Code:
SUBSYSTEM!="usb_device", ACTION!="add", GOTO="objdev_rules_end"
# USBasp
SYSFS{idVendor}=="16c0", SYSFS{idProduct}=="05dc", GROUP="users", MODE="666"
LABEL="objdev_rules_end"

3. Restart udev.
Code:

sudo /etc/init.d/udev restart

(fin de citation)

J'ajoute: déconnecter puis reconnecter la carte programmateur USB ASP pour que les permissions pour l'utilisateur courant soient prises en compte.
J'ai testé le 22 août 2009 sous Ubuntu 9.04, ça marche.

Voir aussi sur mon blog: http://silicium628.blogspot.com/ (vous pouvez y poser des questions ou ajouter des commentaires, des astuces, des conseils...)

6 -

Liens...



9262