dspic LCD 3310
dspic 30F3010


This page presents some C routines to print text on a LCD Nokia 3310 with Microchip dspic 30F3010.
Executable and sources are provided.

Version Fr à traduire.

Choix du dspic 30F3010 :

L'intéret de ce dsPIC 30F3010 est que c'est un microcontrôleur 16 bits de chez Microchip, il comporte une interface de communication Série (SPI, SCI c'est-à-dire UART) mais aussi 6 sorties PWM, des entrées ADC (10 bits). Il a un petit noyeau DSP (multiplication) d'où le nom dsPIC par rapport aux PIC bien connus.

La datasheet 70141c du dsPIC 30F3010 renseigne sur la connectique et les registres que l'on utilise pour le programmer.
Il vaut mieux regarder la documentation plus complete de toute la famille dsPIC (70046E).

Connexions du dsPIC 30F3010

Le projet :

Le but est de pouvoir piloter un écran LCD via la liaison série synchrone SPI.
L'écran du Nokia 3310 est très bon marché et se pilote facilement.
De plus, il est graphique. On a développé des bibliothèques pour écrire en français (caractères latins) et en arabe.
Voici quelques photos du projet suivi des fichiers sources.
Image du LCD

Image du LCD, commande V/f de MAS

Debuggage sur pocket pc

branchement sur l'écrna VGA



Voici le prog en version de développement et les schematics.
Il présente aussi la différence, quand on veut sortir une chaîne de caractères avec sprintf ou via un buffer prérempli (voir détail dans lcd3310_try.c) :
   
  1.   InterruptLED=1;
  2.             sprintf(LCDbuffer, "%02d:%02d:%02d",Hour, Min, Sec);
  3.   InterruptLED=0;
  4.             LCD3310_GotoXY(0,2);
  5.             LCD3310_SendMsg(LCDbuffer);
  6.   InterruptLED=1;
  7.             print_heure_LCDbuffer();
  8.   InterruptLED=0;
  9.  
lcd3310 :

Ce programme est le main qui permet d'afficher la font, une horloge, qqes messages...
(Il y a quelques variables et parties qui ne sont pas utilisés dans cette version)

fichier :dl/dspic/lcd3310/lcd3310_try.c
   
  1. //-----------------------------------------------------------------------------
  2. // Mise en oeuvre de l'ecran LCD du Nokia 3310
  3. // transmission par SPI, debug sur UART1 MAX3233E
  4. // dsPIC 30F3010
  5. // L. BAGHLI 10/03/2007 int Timer1 100 us
  6. //-----------------------------------------------------------------------------
  7. #include "p30F3010.h"
  8. #include "lcd3310.h"  // routines d'écriture sur l'ecran LCD et pilotage HP par PWM
  9.  
  10. //Configuration bits
  11. /// Q=10 MHz
  12. _FOSC(CSW_FSCM_OFF & XT_PLL8)//10Mhz *8 = 80 MHz /4 = 20 MIPS maxi pour ce pic
  13. _FWDT(WDT_OFF);
  14. _FBORPOR(PBOR_OFF & BORV_27 & PWRT_16 & MCLR_EN);
  15. _FGS(CODE_PROT_OFF);
  16. //-----------------------------------------------------------------------------
  17. //Program Specific Constants
  18. #define FCY 20000000          //Instruction cycle rate (Osc x PLL / 4) = 20 MIPS
  19. //#define T1Period 2000     // pour 100us à 20 MHz = T1Period = 2000=FCY*100us
  20. #define T1Period 4000     // pour 200us à 20 MHz = T1Period = 4000=FCY*200us
  21. //#define tcntPRD 5000          // combien de fois pour ariver en Te=1s avec des pas de 200us : 5000
  22. #define tcntPRD 500     // combien de fois pour ariver en Te=0.1s avec des pas de 200us : 500
  23. // Conversion Time MAX6675 norm 0.17s  max 0.22 s
  24. //#define tcntPRD 1250          // combien de fois pour ariver en Te=0.25s avec des pas de 200us : 2
  25. #define MILLISEC FCY/20000      // 1 mSec delay constant
  26.  
  27.  
  28. void setup_ports(void);
  29. void DelayNmSec(unsigned int N);
  30. void InitVar();
  31. void InitUART();
  32. void initTimer();
  33.  
  34. char Phrase[]="Lotfi is here";
  35. char LCDbuffer[100];
  36. char LCDbufferTmp[]="xx#xx#xx";
  37. struct {
  38.       unsigned Running    :   1;
  39.       unsigned CheckRX    :  1;
  40.       unsigned SendTX   :    1;
  41.       unsigned SendData  :    1;
  42.       unsigned unused     :  12;
  43.     } Flags;
  44.  
  45. unsigned int tcnt, TimeStamp;;
  46. unsigned int Hour, Min, Sec;
  47. // RS232 -------------------------------------------
  48. unsigned char *TXPtr;
  49. unsigned char *RXPtr;
  50. void InitUART(void);
  51. void SendMsg(void);
  52. #define CR  0x0D
  53. #define LF  0x0A
  54. #define BAUD 19200
  55. #define OffsetTimeStamp 10        // offset in OutData : position de la val de TimeStamp
  56. unsigned char InData[] = {"000000"};
  57. unsigned char OutData[] = {"TimeStamp=0000 Ssr0_T=0000\r\n"};
  58. int SeqComm;    // ttes les 0.5 s
  59. #define SeqCommMax 5000
  60.  
  61. //-----------------------------------------------------------------------------
  62. //  Initialise variables
  63. //-----------------------------------------------------------------------------
  64. void InitVar(void)
  65. {
  66.   tcnt=0; TimeStamp=0;
  67. }
  68. //-----------------------------------------------------------------------------
  69. //  Setup ports
  70. //-----------------------------------------------------------------------------
  71. void setup_ports(void)
  72. {
  73.   // Clear All Ports Prior to defining I/O
  74.   PORTB=0//Initialize LED pin data to off state
  75.   PORTC=0;
  76.   PORTD=0;
  77.   PORTE=0
  78.   // Now set pin direction registers
  79.   TRISB = 0xFFFC;  // RB0 interruptLED, LCD3310_RST / RB1  output, RB2-4 NC inputs 1111|1100
  80.   TRISC = 0xDFFF;  // U1ATX/RC13 in , U1ATX/RC14 out , inutile pour le UART donc 0xFFFF is also ok
  81.   TRISD = 0xFFFC;  // LCD3310_CS  / RD0 out, LCD3310_DC  / RD1 out
  82.   TRISE = 0x0000;  // RE0-RE5  : out, RE5 PWM LCD3310_Speaker
  83.   LCD3310_RST=1;    // pas de RST LCD
  84.   LCD3310_CS = 1;   // Set SPI CS pin du LCD 3310 non actif
  85.   LCD3310_DC = 0;  // Enter Data Mode
  86.   TRISF = 0xFFFB;  // SDI1/RF2 in, SDO1/RF3 out 1011, inutile pour le SPI donc 0xFFFF is ok
  87. }
  88.  
  89. //-----------------------------------------------------------------------------
  90. //  intitialise timer 1 et l interruption
  91. //-----------------------------------------------------------------------------
  92. void initTimer(void)
  93. {
  94. // Timer1 pour l ISR des 100 us
  95.   T1CON = 0;          // ensure Timer 1 is in reset state, internal timer clock Fosc/4, no prescale
  96.   TMR1  = 0;          // RAZ Timer1
  97.   IFS0bits.T1IF = 0// reset Timer 1 interrupt flag
  98.   IPC0bits.T1IP = 4// set Timer1 interrupt priority level to 4
  99.   IEC0bits.T1IE = 1// enable Timer 1 interrupt
  100.   PR1 = T1Period;   // set Timer 1 period register
  101.   T1CONbits.TON = 1// enable Timer 1 and start the count
  102. }
  103. //---------------------------------------------------------------------
  104. // Below are the interrupt vectors for the serial receive and transmit
  105. //--------------------------------------------------------------------- 
  106. void __attribute__((__interrupt__)) _U1TXInterrupt(void)
  107. {
  108.   IFS0bits.U1TXIF = 0// clear interrupt flag
  109. }
  110. //---------------------------------------------------------------------
  111. void __attribute__((__interrupt__)) _U1RXInterrupt(void)
  112. {
  113.   IFS0bits.U1RXIF = 0// clear interrupt flag
  114.   *RXPtr = U1RXREG;
  115.   if (*RXPtr == CR)
  116.     {Flags.CheckRX = 1;
  117.     RXPtr = &InData[0];}
  118.   else *RXPtr++;
  119. }
  120. //------------------------------------------------------------------------
  121. //  Transmission over serial
  122. void InitUART(void)
  123. {
  124. // Initialize the UART1 for BAUD = 19,200 
  125.   U1MODE = 0x8400;  // enable + alternate pins
  126. //  U1MODE = 0x8000;  // enable + normal pins
  127.   U1STA = 0x0000;
  128.   U1BRG = ((FCY/16)/BAUD) - 1// set baud to 19200
  129.   IEC0bits.U1RXIE = 1;      // enable RX interrupt
  130.   RXPtr = &InData[0];  // point to first char in receive buffer
  131.   Flags.CheckRX = 0;      // clear rx and tx flags
  132.   Flags.SendTX = 0;
  133.   Flags.SendData = 0;  // clear flag
  134.   SeqComm=SeqCommMax;
  135.   U1STAbits.UTXEN = 1;           // Initiate transmission
  136. }
  137. //----------------------------------------------------
  138. // Convertit un "Word" hexa en "4 chars Hexadécimaux"
  139. // et les sort sur la table en memoire
  140. //----------------------------------------------------
  141. inline void ConvHexa(int Var, int tablePos, unsigned char * table)
  142. { 
  143. int tmp;
  144.       tmp=Var & 0x000F;
  145.       if (tmp<=9)  tmp+=0x30;
  146.           else      tmp+=0x37;
  147.       table[tablePos+3]=tmp;
  148.  
  149.       tmp=Var>>4 & 0x000F;
  150.       if (tmp<=9)  tmp+=0x30;
  151.           else      tmp+=0x37;
  152.       table[tablePos+2]=tmp;
  153.  
  154.       tmp=Var>>8 & 0x000F;
  155.       if (tmp<=9)  tmp+=0x30;
  156.           else      tmp+=0x37;
  157.       table[tablePos+1]=tmp;
  158.  
  159.       tmp=Var>>12 & 0x000F;
  160.       if (tmp<=9)  tmp+=0x30;
  161.           else      tmp+=0x37;
  162.       table[tablePos]=tmp;
  163. }
  164. //----------------------------------------------------
  165. // Convertit un "12 bits" en "4 chars décimaux. 2 chars" xxxx.xx
  166. // maximum : 1023.75 pour 12 bits
  167. // et les sort sur la table en memoire
  168. //----------------------------------------------------
  169. inline void ConvDec(int Var, int tablePos, unsigned char * table)
  170. { 
  171. unsigned int k;
  172. unsigned char c;
  173. // Char
  174.   k = Var>>2;
  175.   c = k/1000;
  176.   if (c > 0)
  177.     k = k - c*1000;
  178.   table[tablePos]  =(c + 0x30);
  179.   c = k/100;
  180.   if (c > 0)
  181.     k = k - c*100;
  182.   table[tablePos+1]=(c + 0x30);
  183.   c = k/10;
  184.   if (c > 0)
  185.     k = k - c*10;
  186.   table[tablePos+2]=(c + 0x30);
  187.   table[tablePos+3]=(char)(k + 0x30);
  188.   // apres la virgule :
  189.   switch (Var & 0x03)
  190.     {
  191.     case 0 :  table[tablePos+5]=0x30;  // xxxx.00
  192.               table[tablePos+6]=0x30; break;
  193.     case 1 :  table[tablePos+5]=0x32;  // xxxx.25
  194.               table[tablePos+6]=0x35; break;
  195.     case 2 :  table[tablePos+5]=0x35;  // xxxx.50
  196.               table[tablePos+6]=0x30; break;
  197.     case 3 :  table[tablePos+5]=0x37;  // xxxx.75
  198.               table[tablePos+6]=0x35; break;
  199.     }
  200. }
  201. //-----------------------------------------------------------------------------
  202. void SendMsg(void)
  203. {
  204. while (*TXPtr)
  205.   {
  206.   while (U1STAbits.UTXBF);
  207.   U1TXREG = *TXPtr++;
  208.   }
  209. }
  210. //------------------------------------------------------------------------
  211. // SendData sends the debug information on the uart at 19200 baud
  212. void SendData()
  213. {
  214. // Codage ASCII de la donnée hexa
  215.   ConvHexa( TimeStamp, OffsetTimeStamp, OutData);    // TimeStamp en Hexa
  216.  
  217. //  Sensor0_Tr=(Sensor0_T >> 3) & 0xFFF;
  218. //  ConvDec( Sensor0_Tr, OffsetSensor0_Tr, OutData);        // Sensor0_T en Hexa
  219.  
  220.   TXPtr = &OutData[0];
  221.   SendMsg();
  222. }
  223. //------------------------------------------------------------------------
  224. // Converti Hour, Min, Sec en ASCII sur LCDbuffer
  225. void print_heure_LCDbuffer()
  226. {
  227. unsigned int k;
  228. unsigned char c;
  229. // Codage ASCII de la donnée  
  230.   k = Hour;
  231.   c = k/10;
  232.   if (c > 0)  k = k - c*10;
  233.   LCDbufferTmp[0] = (c + 0x30);
  234.   LCDbufferTmp[1] = (char)(k + 0x30);
  235.  
  236.   k = Min;
  237.   c = k/10;
  238.   if (c > 0)  k = k - c*10;
  239.   LCDbufferTmp[3] = (c + 0x30);
  240.   LCDbufferTmp[4] = (char)(k + 0x30);
  241.  
  242.   k = Sec;
  243.   c = k/10;
  244.   if (c > 0)  k = k - c*10;
  245.   LCDbufferTmp[6] = (c + 0x30);
  246.   LCDbufferTmp[7] = (char)(k + 0x30);
  247. }
  248. //-----------------------------------------------------------------------------
  249. // Timer1 interrupt fait le calcul et l allumage des LED
  250. // ISR toutes les 200 us
  251. //---------------------------------------------------------------------
  252. void __attribute__((__interrupt__)) _T1Interrupt( void )
  253. {
  254.   IFS0bits.T1IF = 0
  255.  
  256.   if (++tcnt>=tcntPRD) 
  257.             {// ici on est toutes les secondes
  258.             tcnt=0;
  259.             TimeStamp++;
  260.             if (++Sec==60)
  261.                   {
  262.                   Sec=0;
  263.                   if (++Min==60)
  264.                         {
  265.                         Min=0;
  266.                         if (++Hour==24) Hour=0
  267.                         }
  268.                   }
  269.             sprintf(LCDbuffer, "Il est :");
  270.             LCD3310_GotoXY(0,1);
  271.             LCD3310_SendMsg(LCDbuffer);
  272.   InterruptLED=1
  273.             sprintf(LCDbuffer, "%02d:%02d:%02d",Hour, Min, Sec);
  274.   InterruptLED=0
  275.             LCD3310_GotoXY(0,2);
  276.             LCD3310_SendMsg(LCDbuffer);
  277.   InterruptLED=1
  278.             print_heure_LCDbuffer();
  279.   InterruptLED=0
  280.             LCD3310_GotoXY(0,3);
  281.             LCD3310_SendMsg(LCDbufferTmp);
  282.             }
  283.  
  284. // communication dsPIC -> PC
  285.   if (!--SeqComm)  {
  286.                     SeqComm=SeqCommMax;
  287.                     Flags.SendData=1;
  288.                     }
  289.  
  290. }
  291. //-----------------------------------------------------------------------------
  292. //Main routine
  293. int main(void)
  294. {
  295. unsigned int j;
  296.   setup_ports();
  297.  
  298. //-----  Debug  -----------
  299.   LCD3310_RST=1;    // ziada
  300. //  DelayNmSec(50);  // tempo
  301.   DelayNmSec(2000);
  302.   LCD3310_RST=0;    // Reset LCD
  303. //  DelayNmSec(250);
  304.   DelayNmSec(1800);
  305.   LCD3310_RST=1;    // pas de RST LCD
  306.  
  307.   InitPWM_HP_LCD3310();
  308.   InitSPI_LCD3310();
  309.   LCD3310_Clear();
  310.   LCD3310_GotoXY(0,0);
  311. // debug
  312. //while(1); // bloque ici
  313.  
  314. //// écrit une chaine d'essai
  315. //  LCD3310_WriteChar('L');
  316. //  LCD3310_WriteChar('o');
  317. //  LCD3310_WriteChar('t');
  318. //  LCD3310_WriteChar('f');
  319. //  LCD3310_WriteChar('i');
  320.   LCD3310_SendMsg(Phrase);
  321. // debug
  322. //while(1); // bloque ici
  323. //-------------------------
  324.  
  325.   InitVar();
  326.   InitUART();
  327.   initTimer();
  328.  
  329.   InterruptLED=0
  330.   Flags.Running=1;
  331.  
  332.   while(1)
  333.     { 
  334.     if (Flags.SendData)
  335.         {
  336.         SendData();  // send present fs serially
  337.         Flags.SendData = 0;  // clear flag
  338.         }
  339.     } // end of while (1)
  340. }
  341.  
  342. //=============================================================================
  343. //Error traps
  344. //-----------------------------------------------------------------------------
  345. //Oscillator Fail Error trap routine
  346. void _ISR _OscillatorFail(void)
  347. { 
  348.   InterruptLED=0
  349.   while(1); //Wait forever
  350. }
  351. //-----------------------------------------------------------------------------
  352. //Address Error trap routine
  353. void _ISR _AddressError(void)
  354. {
  355.   InterruptLED=0
  356.   while(1); //Wait forever
  357. }
  358. //-----------------------------------------------------------------------------
  359. //Stack Error trap routine
  360. void _ISR _StackError(void)
  361. {
  362.   InterruptLED=0
  363.   while(1); //Wait forever
  364. }
  365. //-----------------------------------------------------------------------------
  366. //Math (Arithmetic) Error trap routine
  367. void _ISR _MathError(void)
  368. {
  369.   InterruptLED=0
  370.   while(1); //Wait forever
  371. }
  372. //---------------------------------------------------------------------
  373. // This is a generic 1ms delay routine to give a 1mS to 65.5 Seconds delay
  374. // For N = 1 the delay is 1 mS, for N = 65535 the delay is 65,535 mS.
  375. // Note that FCY is used in the computation.  Please make the necessary
  376. // Changes(PLLx4 or PLLx8 etc) to compute the right FCY as in the define
  377. // statement above.
  378. //---------------------------------------------------------------------
  379. void DelayNmSec(unsigned int N)
  380. {
  381. unsigned int j;
  382. while(N--)
  383.   for(j=0;j < MILLISEC;j++);
  384. }
  385. //---------------------------------------------------------------------
  386.  

Voici les routines :

fichier :dl/dspic/lcd3310/lcd3310.c
   
  1. //-----------------------------------------------------------------------------
  2. // Routines d'affichage sur l'ecran LCD du Nokia 3310
  3. // transmission par SPI
  4. // dsPIC 30F3010
  5. // L. BAGHLI 10/04/2007
  6. //-----------------------------------------------------------------------------
  7. #include "p30F3010.h"
  8. #include "lcd3310.h"
  9.  
  10. unsigned int HalfDUTY;
  11.  
  12. //-----------------------------------------------------------------------------
  13. //  Config Haut parleur de l'ecran LCD via PWM 50% à freq variable
  14. //-----------------------------------------------------------------------------
  15. void InitPWM_HP_LCD3310()
  16. {
  17.   HalfDUTY=T_1000Hz;  // la frequence est variable !
  18.   PTPER = HalfDUTY;  // set the pwm period register, ne pas oublier la double précision
  19.   PWMCON1 = 0x0740;  // enable PWMs tt le tps
  20.   PDC3=HalfDUTY;      // init sans rien, apres une regul ça change
  21.   OVDCON = 0xFFFF;  // Cmde MLI, no effect of OVDCON
  22.   PWMCON2 = 0x0000;  // 1 PWM values
  23.   PTCON = 0x8002;   // start PWM symetrique
  24. }
  25. //-----------------------------------------------------------------------------
  26. //  Init SPI du LCD
  27. //-----------------------------------------------------------------------------
  28. void InitSPI_LCD3310()
  29. {
  30.   SPI1CON = 0x0123;  // Master mode, SCK = Fcy/8 = 2.5 MHz, CKP=0, CKE=1, Clk idle is low, 8 bits
  31.   SPI1STAT = 0x8000;  // Enable SPI port
  32.   LCD3310_Send( 0x21, LCD_CMD )// LCD Extended Commands.
  33.   LCD3310_Send( 0xC8, LCD_CMD )// Set LCD Vop (Contrast).
  34. //  LCD3310_Send( 0x80, LCD_CMD );  // Set LCD Vop (Contrast).
  35.   LCD3310_Send( 0x06, LCD_CMD )// Set Temp coefficent.
  36.   LCD3310_Send( 0x13, LCD_CMD )// LCD bias mode 1:48.
  37.   LCD3310_Send( 0x20, LCD_CMD )// LCD Standard Commands, Horizontal addressing mode.
  38.   LCD3310_Send( 0x0C, LCD_CMD )// LCD in normal mode.
  39. //  LCD3310_Send( 0x0D, LCD_CMD );  // LCD in inverse videoe.
  40. }
  41. //---------------------------------------------------------------------
  42. // Set the current position for data (x = 0->83, y = 0->5)
  43. void LCD3310_Clear()
  44. {
  45. unsigned int x, y;
  46.   for (y=0; y<6; y++)
  47.     for (x=0; x<84; x++)
  48.       LCD3310_Send( 0x00, LCD_DATA );  // caractère vide
  49. }
  50. //---------------------------------------------------------------------
  51. // Set the current position for data (x = 0->83, y = 0->5)
  52. void LCD3310_GotoXY(unsigned short xnokia, unsigned short ynokia)
  53. {
  54.   LCD3310_Send( 0x40 | ( ynokia & 0x07), LCD_CMD );  // new y cursor position
  55.   LCD3310_Send( 0x80 | ( xnokia & 0x7f), LCD_CMD );  // new x cursor position
  56. }
  57. //-----------------------------------------------------------------------------
  58. // Affiche une phrase à l'écran
  59. void LCD3310_SendMsg(char *dataPtr )
  60. {
  61.   while ( *dataPtr )
  62.     LCD3310_WriteChar( *dataPtr++ );
  63. }
  64. //-----------------------------------------------------------------------------
  65. // Affiche un caractere à l'écran
  66. void LCD3310_WriteChar(char ascii_code)
  67. { //20+ascii_code
  68.   if (ascii_code<0x20)  return;
  69.   LCD3310_Send( FontLookup [ascii_code-0x20][0], LCD_DATA );    // bout de char
  70.   LCD3310_Send( FontLookup [ascii_code-0x20][1], LCD_DATA );    // bout de char
  71.   LCD3310_Send( FontLookup [ascii_code-0x20][2], LCD_DATA );    // bout de char
  72.   LCD3310_Send( FontLookup [ascii_code-0x20][3], LCD_DATA );    // bout de char
  73.   LCD3310_Send( FontLookup [ascii_code-0x20][4], LCD_DATA );    // bout de char
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Envoie le caractere à afficher sur l'ecran
  77. void LCD3310_Send(unsigned short data, unsigned short cd )
  78. {
  79. unsigned int uidummy;
  80.   if (cd==LCD_DATA) LCD3310_DC = 1;      // Enter Data Mode
  81.       else          LCD3310_DC = 0;   // Enter Command Mode
  82.   SPI1STATbits.SPIROV = 0;            // Clear overflow flag
  83.   LCD3310_CS = 0;     // Set SPI CS pin du LCD 3310 actif
  84.   uidummy = SPI1BUF;                    // Read buffer to avoid overflow
  85.   SPI1BUF=data; while (SPI1STATbits.SPITBF)while ( !SPI1STATbits.SPIRBF)// char
  86. //  for(uidummy=0;uidummy < SPI_8bitsdelay;uidummy++);  // tps d'attente
  87.   LCD3310_CS = 1;     // Set SPI CS pin du LCD 3310 non actif
  88. }
  89. //-----------------------------------------------------------------------------
  90.  

N'oubliez pas de télécharger toute la librairie.

Download executable and sources.
Download :
lcd3310_lib.zip   Sources C du projet.


Back to homepage

Last update : 18/05/2007