Programming dsPIC MCU in C

Chapter13: Examples

Example 1 – Operating alpha-numeric LCD module by using 4-bit interface

The example shows the connection of an alpha-numeric LCD module 2x16 characters to a dsPIC30F microcontroller by using a 4-bit interface. The following code demonstrates usage of the LCD Custom Library routines. The example covers the initialization of the LCD module and instructions for contolling and writing the module. The realization is carried out by using the mikroC compiler for dsPIC30F microcontrollers. The interconnection of the LCD module and a dsPIC30F device by using a 4-bit interface is shown in Fig. 13-1.

Interconnection of the LCD module and a dsPIC30F device by using a 4-bit interface

Fig. 13-1 Interconnection of the LCD module and a dsPIC30F device by using a 4-bit interface

char text[6] = "mikro";

void main() {

  //--- PORTB - all digital
  ADPCFG = 0xFFFF;

  Lcd_Custom_Config(&PORTB, 3,2,1,0, &PORTD, 0,2,1);
  Lcd_Custom_Out(1,3, text);
  Lcd_Custom_Out(2,6, text);
  Lcd_Custom_Chr(2,7, 'a');
  Lcd_Custom_Out(1,10, text);
  Lcd_Custom_Chr(1,11, 'o');
}//~!

Example 2 – Operating alpha-numeric LCD module by using 8-bit interface

The example shows the connection of an alpha-numeric LCD module 2x16 characters to a dsPIC30F microcontroller by using an 8-bit interface. The following code demonstrates usage of the LCD 8-bit Library routines. The example covers the initialization of the LCD module and instructions for contolling and writing the module. The realization is carried out by using the mikroC compiler for dsPIC30F microcontrollers. The interconnection of the LCD module and a dsPIC30F device by using an 8-bit interface is shown in Fig. 13-2.

Interconnection of the LCD module and a dsPIC30F device by using a 8-bit interface

Fig. 13-2 Interconnection of the LCD module and a dsPIC30F device by using a 8-bit interface

void main(){

  //--- PORTB - all digital
  ADPCFG = 0xFFFF;

  Lcd8_Custom_Config(&PORTB, 7, 6, 5, 4, 3, 2, 1, 0, &PORTD, 0, 1, 2);
  Lcd8_Custom_Cmd(LCD_CLEAR);
  Lcd8_Custom_Cmd(LCD_CURSOR_OFF);

  Lcd8_Custom_Out(1, 1, "mikroElektronika");
  Lcd8_Custom_Chr(2, 1,'c');
  Lcd8_Custom_Chr_CP('?');
  Lcd8_Custom_Out_CP("for_dsPIC");
}//~!

Example 3 – Operating a graphical alpha-numeric LCD module (GLCD)

The example shows the connection of a «dot-matrix» graphical alpha-numeric LCD module (GLCD) to a dsPIC30F microcontroller. The example covers the initialization of the GLCD, writing text, drawing lines, boxes, and circles. The realization is carried out by using the mikroC compiler for dsPIC30F microcontrollers. The interconnection of the GLCD module and a dsPIC30F device is shown in Fig. 13-3.

Interconnection of the GLCD module and a dsPIC30F device

Fig. 13-3 Interconnection of the GLCD module and a dsPIC30F device.

#include "bmp1.h"

char cArr[20];
char *someText;

void Delay2S(){
  delay_ms(2000);
}//~


void main() {
  unsigned short ii;
  unsigned int jj;


  sometext = cArr;

  //--- turn off A/D inputs
  ADPCFG = 0xFFFF;
  // Init for dsPICPRO3 development system
  Glcd_Init(&PORTB, 2, &PORTB,3, &PORTB,4, &PORTB,5, &PORTB,7, &PORTB,6, &PORTD);
  Delay_100ms();

  lMainLoop:

  Glcd_Fill(0x00);
  Glcd_Image( maska_bmp );
  Delay2S();

  Glcd_Fill(0x00);
  Glcd_Circle(63,32, 20, 1);
  Delay2S();
  Glcd_Line(120,1, 5,60, 1);
  Glcd_Line(12,42, 5,60, 1);
  Delay2S();

  Glcd_Rectangle(12,20, 93,57, 1);
  Delay2S();

  Glcd_Line(120,12, 12,60, 1);
  Delay2S();

  Glcd_H_Line(5,15, 6, 1);
  Glcd_Line(0,12, 120,60, 1);
  Glcd_V_Line(7,63, 127, 1);
  Delay2S();

  for (ii = 1; ii <= 10; ii++)
    Glcd_Circle(63,32, 3*ii, 1);
  Delay2S();

  Glcd_Box(12,20, 70,57, 2);
  Delay2S();

  Glcd_Set_Font(defaultFont, 5,7, 48);
  someText = "BIG:ONE";
  Glcd_Write_Text(someText, 5,3, 2);
  Delay2S();


  someText = "SMALL:NOT:SMALLER";
  Glcd_Write_Text(someText, 20,5, 1);
  Delay2S();

  Glcd_Fill(0x00);
  Glcd_Set_Font(System3x6, 3, 6, 0x20);
  Glcd_Write_Text(someText, 10,5, 1);
  Delay2S();

  goto lMainLoop;
}//~!

Example 4 – Operating an AD converter

The example shows sampling by an AD converter and sends it as a text via UART1. The realization is carried out by using the mikroC compiler for dsPIC30F microcontrollers. Fig. 13-4 shows the connection of a dsPIC30F6014A microcontroller for sampling the voltages of the sliding contact of a potentiometer connected to the pin AN10 and sending it as a text via UART1.

Connection of a dsPIC30F6014A device in order to sample on pin AN10

Fig. 13-4 Connection of a dsPIC30F6014A device in order to sample on pin AN10

unsigned adcRes;
char txt[6];

void Uart1_Write_Text(char *txt_to_wr) {
  while (*txt_to_wr)
  Uart1_Write_Char(*(txt_to_wr++));
}

void main() {

  TRISBbits.TRISB10 = 1; // set pin as input - needed for ADC to work

  Uart1_Init(9600);

  while (1) {
    adcRes = Adc_Read(10);
    WordToStr(adcRes, txt);
    Uart1_Write_Text(txt);
    Delay_ms(50);
  }
}//~!

Example 5 – Operating a 4 x 4 keyboard

The example shows the connection of a 4 x 4 keyboard to a dsPIC30F6014A microcontroller. The example shows decoding the keyboard [0...15] to obtain ASCII symbols [0...9,A...F]. Also shown is a counter of the pressed keys. The value of the counter is written in the second line of an LCD module. The realization is carried out by using the mikroC compiler for dsPIC30F microcontrollers. Fig. 13-5 shows the interconnection of the keyboard and a dsPIC30F6014A microcontroller.

Interconnection of the keyboard and a dsPIC30F6014A microcontroller

Fig. 13-5 Interconnection of the keyboard and a dsPIC30F6014A microcontroller

unsigned kp;

void main() {

  ADPCFG = 0xFFFF;

  Keypad_Init(&PORTB);   // PORTB [7..0]
  Uart1_Init(9600);
  Delay_ms(200);
  Uart1_Write_Char('R');

  do {
    //--- Wait for key to be pressed
    do {
      //kp = Keypad_Key_Click();     // choose the key detecting function
      kp = Keypad_Key_Press();
    } while (!kp);

    //--- Prepare value for output
    switch (kp) {
    
    
    // uncomment this block for keypad4x3 //

      /* case 10: kp = 42; break;  // '*'
         case 11: kp = 48; break;  // '0'
         case 12: kp = 35; break;  // '#'
         default: kp += 48;                      */
      
      

    // uncomment this block for keypad4x4 //
    
      case  1: kp = 49; break; // 1
      case  2: kp = 50; break; // 2
      case  3: kp = 51; break; // 3
      case  4: kp = 65; break; // A
      case  5: kp = 52; break; // 4
      case  6: kp = 53; break; // 5
      case  7: kp = 54; break; // 6
      case  8: kp = 66; break; // B
      case  9: kp = 55; break; // 7
      case 10: kp = 56; break; // 8
      case 11: kp = 57; break; // 9
      case 12: kp = 67; break; // C
      case 13: kp = 42; break; // *
      case 14: kp = 48; break; // 0
      case 15: kp = 35; break; // #
      case 16: kp = 68; break; // D

    }

    //--- Send on UART1
    Uart1_Write_Char(kp);

  } while (1);
} //~!

Also, an example is given of the clearance by the software of the errors caused by the keyborad bounsing using the same connection as shown in Fig. 13-5. The realization is carried out by using the mikroC compiler for dsPIC30F microcontrollers.

unsigned int oldstate;

void main() {
  ADPCFG = 0xFFFF;
  TRISB = 0xFFFF;
  TRISD = 0x0000;
  
  do {
    if (Button(&PORTB, 0, 1, 1))
      oldstate = 1;
    if (oldstate && Button(&PORTB, 0, 1, 0)) {
      LATD = ~LATD;
      oldstate = 0;
    }
  } while(1);
}

Example 6 – Realization of pulse width modulation

The example shows the realization of continuously varying pulse width modulation (PWM). The continously modulated output is on the PORTE.0 pin which is monitored by a LED diode. The realization is carried out by using the mikroC compiler for dsPIC30F microcontrollers. Fig. 13-6 shows the electric diagram of the realized continuous PWM of a LED diode connected to PORTE.0.

electric diagram of the realized continuous PWM of a LED diode connected to PORTE.0

Fig. 13-6 The electric diagram of the realized continuous PWM of a LED diode connected to PORTE.0.

unsigned int i;

unsigned int duty_50;

void main(){
      ADPCFG = 0xFFFF;
      PORTB = 0xAAAA;
      TRISB = 0;
      Delay_ms(1000);

      duty_50 = Pwm_Mc_Init(5000,1,0x01,0);           // Pwm_Mc_Init returns 50% of the duty
      Pwm_Mc_Set_Duty(i = duty_50,1);
      Pwm_Mc_Start();

      do
      {
        i--;
        Pwm_Mc_Set_Duty(i,1);
        Delay_ms(1);
        if (i == 0)
          i = duty_50 * 2 - 1;                    // Let us not allow  overflow
        PORTB = i;
      }
      while(1);
}//~

Example 7 – Operating a compact flash memory card

The example shows the connection of a compact flash (CF) memory card to a dsPIC30F micocontroller. The CF memory cards are often used as the memory elements in digital video cameras. The memory capacity is high, from 8MB up to 2GB even more, and the read/write time is typically of the order of µs. Application of CF memory cards in microcontroller systems is quite widespread.

In the CF memory cards data are split into sectors (usually of 512 bytes, in earlier models 256 bytes). Reading or writing is not performed directly byte after byte, but data are blocked per sectors through a 512 byte buffer. Fig. 13-7 shows the electrical connection of a CF memory card to a device of the dsPIC30F family. The realization is carried out by using the mikroC compiler for dsPIC30F microcontrollers. The example covers, writing and reading one byte from a CF memory card.

Electrical connection of a CF memory card to a device of the dsPIC30F family

Fig. 13-7 Electrical connection of a CF memory card to a device of the dsPIC30F family.

char buff[512];

//-------------- Init for dsPICPRO2
void Cf_Init_dsPICPRO2() {

  Cf_Init(&PORTD,8,9,10, &PORTG,14, &PORTG,12, &PORTD,11, &PORTG,15, &PORTG,13, &PORTD);

}//~


void initCF() {
  ADPCFG = 0xFFFF;
  Cf_Init_dsPICPRO2();
  
  //--- CD1 does not work on non-TTL inputs
  //while (CF_Detect() == 0) ;              // wait until CF card is inserted
  //Delay_ms(500);                          // wait for a while until the card is stabilized
}//~


//--------------
void testBytes() {
  unsigned int i, tmp;

  //--- write some data
  CF_Write_Init(620,1);                   // Initialize writing at sector address 620
                                          //     for 1 sector (byte)
  Uart1_Write_Char('s');                  // Notify that writing has started
  Delay_ms(1000);
  for (i=0; i<=511; i++) {                // Write 512 bytes to sector 590
    CF_Write_Byte(i);
  }
  Delay_ms(1000);

  //--- read written data
  CF_Read_Init(620,1);                    // Initialize read from sector address 620
  Delay_ms(1000);
                                          //    for 1 sector (byte)
  Cf_Read_Sector(620, buff);
  for (i=0; i<=511; i++) {                // Read 512 bytes from initialized sector
    Uart1_Write_Char(buff[i]);
 }
}//~



//-------------- Main program
void main() {
  Uart1_Init(19200);

  initCF();
  testBytes();
}//~!

Example 8 – Operating UART modules

The example shows the initialization, writing, and reading data from the transmitter and receiver of an UART module, respectively. The realization is carried out by using the mikroC compiler for dsPIC30F microcontrollers. Fig. 13-8 shows the electrical connection of an UART module to an RS-232 transiever and further connection to the serial port of a PC.

Electrical connection of an UART module to an RS-232 transiever and further connection to the serial port of a PC

Fig. 13-8 Electrical connection of an UART module to an RS-232 transiever and further connection to the serial port of a PC.

unsigned rx1;

void main() {

  Uart1_Init(9600);
  Uart1_Write_Char('s');

  while(1)
  {
    if (Uart1_Data_Ready())  {
     rx1 = Uart1_Read_Char();
     Uart1_Write_Char(rx1);
    }
  }
}

Example 9 – Operating SPI modules

The example shows the initialization, writing, and reading data from the receive and transmit buffer register of an SPI module, respectively. The example shows the connection of the SPI2 module to the serial digital-to-analogue converter (DAC) MCP4921. The realization is carried out by using the mikroC compiler for dsPIC30F microcontrollers. Fig. 13-9 shows the electrical connection of the SPI module to the serial DAC MCP4921.

Electrical connection of the SPI module to the serial DAC MCP4921

Fig. 13-9 Electrical connection of the SPI module to the serial DAC MCP4921.

const char CS_PIN = 1;
const char LD_PIN = 2;

unsigned int value;

void InitMain() {
  ADPCFG = 0xFFFF;                        // Set AN pins as digital

  Spi2_Init();                            // Initialize SPI2 module

  TRISC.CS_PIN = 0;                       // Set CS pin as output
  TRISC.LD_PIN = 0;                       // Set LD pin as output
}//~


// DAC increments (0..4095) --> output voltage (0..Vref)
void DAC_Output(unsigned int valueDAC) {
 char temp;

  PORTC.CS_PIN = 0;                       // Select DAC module
  PORTC.LD_PIN = 0;                       // Enable data transfer

  // Send 2 bytes of valueDAC variable
  temp = (valueDAC >> 8) & 0x0F;          // Prepare hi-byte for transfer
                                          // It's a 12-bit number, so only
                                          // lower nibble of high byte is used
  temp |= 0x30;                           // Set MCP4921 control bits
  Spi2_Write(temp);                       // Send data via SPI

  temp = valueDAC;                        // Prepare lo-byte for transfer
  Spi2_Write(temp);                       // Send data via SPI

  PORTC.LD_PIN = 1;                       // Disable data transfer
  PORTC.CS_PIN = 1;                       // Deselect DAC module
}//~


void main() {
  InitMain();

  value = 2047;                           // When program starts, DAC gives
                                          // the output in the mid-range

  while (1) {                             // Main loop
    DAC_Output(value++);
    if (value > 4095)
      value = 0;
    Delay_ms(5);
  }
}//~!

Example 10 – Operating Secure Digital memory cards

Secure Digital (SD) is a standard flash memory card based on the earlier Multi Media Card (MMC) standard. Similarly to the CF memory cards, the SD memory cards have a high memory capacity, up to 2GB, and have found the application in the mobile phones, MP3 players, digital cameras, and PDA computers. Access to an SD memory card is realized by using the SPI communication interface.

This example consists of several blocks that demonstrat various aspects of usage of the Mmc_Fat16 library. These are: Creation of new file and writing down to it; Opening existing file and re-writing it (writing from start-of-file); Opening existing file and appending data to it (writing from end-of-file); Opening a file and reading data from it (sending it to USART terminal); Creating and modifying several files at once; Reading file contents; Deleting file(s); Creating the swap file (see Help for details);

Electrical connection of the SD memory card to a device from the dsPIC30F family

Fig. 13-10 Electrical connection of the SD memory card to a device from the dsPIC30F family.

#include <spi_const.h>

const char SWAP_FILE_MSG[] = "Swap file at: ";

char
 fat_txt[20] = "FAT16 not found",
 file_contents[50] = "XX MMC/SD FAT16 library by Anton Rieckertn";

char
 filename[14] = "MIKRO00xTXT";          // File names
unsigned
 loop, loop2;
unsigned short
 caracter;
unsigned long
 i, size;
char Buffer[512];

//I-I-I--------- Writes string to USART
void I_Write_Str(char *ostr) {
  unsigned i;

  i = 0;
  while (ostr[i]) {
    Uart1_Write_Char(ostr[i++]);
  }
}//~

//M-M-M--------- Creates a new file and writes some data to it
void M_Create_New_File() {
  filename[7] = 'A';
  Mmc_Fat_Assign(&filename, 0xA0);         // Will not find file and then create file
  Mmc_Fat_Rewrite();                    // To clear file and start with new data
  for(loop = 1; loop <= 99; loop++) {   //  We want 5 files on the MMC card
    Uart1_Write_Char('.');
    file_contents[0] = loop / 10 + 48;
    file_contents[1] = loop % 10 + 48;
    Mmc_Fat_Write(file_contents, 42);   // write data to the assigned file
  }
}//~

//M-M-M--------- Creates many new files and writes data to them
void M_Create_Multiple_Files() {
  for(loop2 = 'B'; loop2 <= 'Z'; loop2++) {
    Uart1_Write_Char(loop2);             // signal the progress
    filename[7] = loop2;                 // set filename
    Mmc_Fat_Assign(&filename, 0xA0);        // find existing file or create a new one
    Mmc_Fat_Rewrite();                   // To clear file and start with new data
    for(loop = 1; loop <= 44; loop++) {
      file_contents[0] = loop / 10 + 48;
      file_contents[1] = loop % 10 + 48;
      Mmc_Fat_Write(file_contents, 42);  // write data to the assigned file
    }
  }
}//~

//M-M-M--------- Opens an existing file and rewrites it
void M_Open_File_Rewrite() {
  filename[7] = 'C';
  Mmc_Fat_Assign(&filename, 0);
  Mmc_Fat_Rewrite();
  for(loop = 1; loop <= 55; loop++) {
    file_contents[0] = loop / 10 + 64;
    file_contents[1] = loop % 10 + 64;
    Mmc_Fat_Write(file_contents, 42);    // write data to the assigned file
  }
}//~

//M-M-M--------- Opens an existing file and appends data to it
//               (and alters the date/time stamp)
void M_Open_File_Append() {
     filename[7] = 'B';
     Mmc_Fat_Assign(&filename, 0);
     Mmc_Fat_Set_File_Date(2005,6,21,10,35,0);
     Mmc_Fat_Append();                                    // Prepare file for append
     Mmc_Fat_Write(" for mikroElektronika 2005n", 27);   // Write data to the assigned file
}//~

//M-M-M--------- Opens an existing file, reads data from it and puts it to USART
void M_Open_File_Read() {
  filename[7] = 'B';
  Mmc_Fat_Assign(&filename, 0);
  Mmc_Fat_Reset(&size);                 // To read file, function returns size of file
  for (i = 1; i <= size; i++) {
    Mmc_Fat_Read(&caracter);
    Uart1_Write_Char(caracter);         // Write data to USART
  }
}//~

//M-M-M--------- Deletes a file. If the file doesn't exist, it will first be created
//               and then deleted.
void M_Delete_File() {
  filename[7] = 'F';
  Mmc_Fat_Assign(filename, 0);
  Mmc_Fat_Delete();
}//~

//M-M-M--------- Tests whether file exists, and if so sends its creation date
//               and file size via USART
void M_Test_File_Exist(char fLetter) {
  unsigned long fsize;
  unsigned int year;
  unsigned short month, day, hour, minute;
  unsigned char outstr[12];

  filename[7] = fLetter;
  if (Mmc_Fat_Assign(filename, 0)) {
    //--- file has been found - get its date
    Mmc_Fat_Get_File_Date(&year, &month, &day, &hour, &minute);
    WordToStr(year, outstr);
    I_Write_Str(outstr);
    ByteToStr(month, outstr);
    I_Write_Str(outstr);
    WordToStr(day, outstr);
    I_Write_Str(outstr);
    WordToStr(hour, outstr);
    I_Write_Str(outstr);
    WordToStr(minute, outstr);
    I_Write_Str(outstr);
    //--- get file size
    fsize = Mmc_Fat_Get_File_Size();
    LongToStr((signed long)fsize, outstr);
    I_Write_Str(outstr);
  }
  else {
    //--- file was not found - signal it
    Uart1_Write_Char(0x55);
    Delay_ms(1000);
    Uart1_Write_Char(0x55);
  }
}//~

//-------------- Tries to create a swap file, whose size will be at least 100
//               sectors (see Help for details)
void M_Create_Swap_File() {
  unsigned int i;

  for(i=0; i<512; i++)
    Buffer[i] = i;

  size = Mmc_Fat_Get_Swap_File(5000, "mikroE.txt", 0x20);
  // see help on this function for details

  if (size) {
    LongToStr((signed long)size, fat_txt);
    I_Write_Str(fat_txt);

    for(i=0; i<5000; i++) {
      Mmc_Write_Sector(size++, Buffer);
      Uart1_Write_Char('.');
    }
  }
}//~

//-------------- Main. Uncomment the function(s) to test the desired operation(s)
void main() {
     //--- prepare PORTD for signalling
     PORTD = 0;
     TRISD = 0;
     ADPCFG = 0xFFFF;
     //--- set up USART for the file read
     Spi1_Init_Advanced(_SPI_MASTER, _SPI_8_BIT, _SPI_PRESCALE_SEC_1, _SPI_PRESCALE_PRI_64,
_SPI_SS_DISABLE, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_HIGH, _SPI_ACTIVE_2_IDLE);

     Uart_Init(19200);
     U1MODEbits.ALTIO = 1;               // clear the way for SPI
     Delay_ms(200);                      // wait for the UART module to stabilize
     //--- init the FAT library
     if (!Mmc_Fat_Init(&PORTB,8)) {
         // reinitialize spi at higher speed
         Spi1_Init_Advanced(_SPI_MASTER, _SPI_8_BIT, _SPI_PRESCALE_SEC_1, _SPI_PRESCALE_PRI_4,
_SPI_SS_DISABLE, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_HIGH, _SPI_ACTIVE_2_IDLE);
         //--- Test start
         PORTD = 0x0005;
         
         //--- Test routines. Uncomment them one-by-one to test certain features
         M_Create_New_File();
         M_Create_Multiple_Files();

         M_Open_File_Rewrite();
         M_Open_File_Append();
         M_Delete_File();
         M_Create_Swap_File();

         M_Open_File_Read();
         M_Test_File_Exist('F');         // this file will not exist here
         M_Test_File_Exist('B');         // this file will exist here

    }
     else {
       I_Write_Str(fat_txt);
     }
     //--- Test termination
     PORTD = 0xFFFF;
}//~!

Example 11 – Operating I2C modules

The example shows the initialization, writing, and reading data from the transmit and receive buffer register ofan I2C module, respectively. The example shows the connection of an I2C module to the serial EEPROM memory 24C02. The realization is carried out by using the mikroC compiler for dsPIC30F microcontrollers. Fig. 13-11 shows the electrical connection of an I2C module to the EEPROM memory 24C02. The example covers writing to the EEPROM memory, reading data, and data transfer to the PORTF.

Electrical connection of an I2C module to the EEPROM memory 24C02

Fig. 13-11 Electrical connection of an I2C module to the EEPROM memory 24C02.

void main() {
  ADPCFG = 0xFFFF;
  PORTB = 0;
  TRISB = 0;
  
  dAddr = 0x02;

  I2c_Init(100000);
  I2c_Start();                   // issue I2C start signal
  I2c_Write(0xA2);               // send byte via I2C  (command to 24cO2)
  I2c_Write(dAddr);              // send byte (address of EEPROM location)
  I2c_Write(0xF4);               // send data (data to be written)
  I2c_Stop();

  Delay_100ms();

  I2c_Start();                   // issue I2C start signal
  I2c_Write(0xA2);               // send byte via I2C  (device address + W)
  I2c_Write(0x02);               // send byte (data address)
  I2c_Restart();                 // issue I2C signal repeated start
  I2c_Write(0xA3);               // send byte (device address + R)
  PORTB = I2c_Read(1);           // Read the data (NO acknowledge)
  I2c_Stop();

}//~!

Also, an example is presented showing the connection of a device from the dsPIC30F family to the RTC (Real-Time Clock) generator Philips PCF8583P. The example covers writing to and reading from the RTC generator by using an I2C standard interface. Date and time are printed at LCD.

//RTCWrite

void main() {
   ADPCFG = 0xFFFF;
   I2C_Init(10000);         // initialize full master mode
   I2C_Start();             // issue start signal
   I2C_Write(0xA0);         // address PCF8583
   I2C_Write(0);            // start from word at address 0 (configuration word)
   I2C_Write(0x80);         // write 0x80 to config. (pause counter...)
   I2C_Write(0);            // write 0 to cents word
   I2C_Write(0);            // write 0 to seconds word
   I2C_Write(0x30);         // write 0x30 to minutes word
   I2C_Write(0x11);         // write 0x11 to hours word
   I2C_Write(0x24);         // write 0x24 to year/date word
   I2C_Write(0x08);         // write 0x08 to weekday/month
   I2C_Stop();              // issue stop signal

   I2C_Start();             // issue start signal
   I2C_Write(0xA0);         // address PCF8530
   I2C_Write(0);            // start from word at address 0
   I2C_Write(0);            // write 0 to config word (enable counting)
   I2C_Stop();              // issue stop signal
}//~!

//RTCRead
 
unsigned char sec, min1, hr, day, mn, year;
char *txt, tnum[4];

void Zero_Fill(char *value) {    // fill text repesentation
  if (value[1] == 0) {           //      with leading zero
    value[1] = value[0];
    value[0] = 48;
    value[2] = 0;
  }
}//~

//--------------------- Reads time and date information from RTC (PCF8583)
void Read_Time(char *sec, char *min, char *hr, char *day, char *mn, char *year) {
  I2C_Start();
  I2C_Write(0xA0);
  I2C_Write(2);
  I2c_Restart();
  I2C_Write(0xA1);
  *sec =I2c_Read(0);
  *min =I2c_Read(0);
  *hr =I2c_Read(0);
  *day =I2c_Read(0);
  *mn =I2c_Read(1);
  I2C_Stop();
}//~

//-------------------- Formats date and time
void Transform_Time(char  *sec, char *min, char *hr, char *day, char *mn, char *year) {
  *sec  =  ((*sec & 0xF0) >> 4)*10 + (*sec & 0x0F);
  *min  =  ((*min & 0xF0) >> 4)*10 + (*min & 0x0F);
  *hr   =  ((*hr & 0xF0) >> 4)*10 + (*hr & 0x0F);
  *year =  (*day & 0xC0) >> 6;
  *day  =  ((*day & 0x30) >> 4)*10 + (*day & 0x0F);
  *mn   =  ((*mn & 0x10) >> 4)*10 + (*mn & 0x0F);
}//~

//-------------------- Output values to LCD
void Display_Time(char sec, char min, char hr, char day, char mn, char year) {
   ByteToStr(day,tnum);
   txt = rtrim(tnum);
   Zero_Fill(txt);
   Lcd_Custom_Out(1,6,txt);
   ByteToStr(mn,tnum);
   txt = rtrim(tnum);
   Zero_Fill(txt);
   Lcd_Custom_Out(1,9,txt);
   Lcd_Custom_Chr(1,15,52+year);
   ByteToStr(hr,tnum);
   txt = rtrim(tnum);
   Zero_Fill(txt);
   Lcd_Custom_Out(2,6,txt);
   ByteToStr(min,tnum);
   txt = rtrim(tnum);
   Zero_Fill(txt);
   Lcd_Custom_Out(2,9,txt);
   ByteToStr(sec,tnum);
   txt = rtrim(tnum);
   Zero_Fill(txt);
   Lcd_Custom_Out(2,12,txt);
}//~

//------------------ Performs project-wide init
void Init_Main() {
  ADPCFG = 0xFFFF;
  Lcd_Custom_Init_EasyDsPIC4();
  I2C_Init(100000);         // initialize I2C
  txt = "Date:";            // prepare and output static text on LCD
  Lcd_Custom_Out(1,1,txt);
  Lcd_Custom_Chr(1,8,':');
  Lcd_Custom_Chr(1,11,':');
  txt = "Time:";
  Lcd_Custom_Out(2,1,txt);
  Lcd_Custom_Chr(2,8,':');
  Lcd_Custom_Chr(2,11,':');
  txt = "200";
  Lcd_Custom_Out(1,12,txt);
  Lcd_Custom_Cmd(LCD_CURSOR_OFF);   // cursor off
}//~

//----------------- Main function
void main() {
  Init_Main();                                      // perform initialization
  while (1) {
    Read_Time(&sec,&min1,&hr,&day,&mn,&year);       // read time from RTC(PCF8583)
    Transform_Time(&sec,&min1,&hr,&day,&mn,&year);  // format date and time
    Display_Time(sec, min1, hr, day, mn, year);     // prepare and display on LCD
    Delay_ms(1000);                                 // wait 1s
  }
}

Example 12 – Operating a PS/2 keyboard

The example shows the connection of a device from the dsPIC30F family to a standard PS/2 keyboard. It is important to note that all pins of the PS/2 keyboard connected to the dsPIC30F device are connected to the power supply by the pull-up resistors. The realization is carried out by using the mikroC compiler for dsPIC30F microcontrollers.

unsigned int
 keydata = 0, special = 0, down = 0;

void main() {
  ADPCFG = 0xFFFF;
  Uart1_Init(9600);
  Ps2_Init(&PORTC);         // Init PS/2 Keyboard on PORTC
                            // pin 13 is connected to Data line
                            // pin 14 is connected to Clock line
                            
  Delay_ms(100);            // Wait for keyboard to finish
  Uart1_Write_Char('s'); Uart1_Write_Char('t'); Uart1_Write_Char('a');
  Uart1_Write_Char('r'); Uart1_Write_Char('t'); Uart1_Write_Char('!');
  do {
    if(Ps2_Key_Read(&keydata, &special, &down)) {
      if(down && (keydata == 16)) {// Backspace
        Uart1_Write_Char(0x08);
      }
      else if(down && (keydata == 13)) {// Enter
        Uart1_Write_Char('r');   // send carriage return to usart terminal
        //Uart1_Write_Char('n');//uncomment this line if usart terminal also expects line feed
                                 // for new line transition
      }
      else if(down && !special && keydata) {
        //Uart1_Write_Char(keydata >> 8);
        Uart1_Write_Char(keydata);
      }
    }
    Delay_ms(1);            // debounce
  } while(1);
}//~

previous chapter | table of contents | next chapter