Rabu, 12 Februari 2014

Library koneksi LCD 16x2 HD44780 untuk STM32F4 board

                Pada posting kali ini, kita akan mencoba untuk menghubungkan LCD 16x2 HD44780 (atau clone-nya) dengan board STM32F4 Discovery. Mode yang dipakai adalah mode 3 pin kontrol dan 4 pin data. Semua pin akan dikoneksikan ke PORT E. Bagaimana kah rangkaian untuk memakai LCD? liat aja gambar di bawah ini.



                Disitu tampak kalau ada variable resistor yang terpasang di 3 pin LCD yang diunakan untuk mengatur contras dari LCD yang dipakai. Konfigurasi tersebut bisa di rubah ke port lain dengan meng-edit di file hd44780.h.  Konfigurasi pin dari LCD dan board STM32F4 adalah sebagai berikut:
    - LCD_D4 >>> PORTE 14
    - LCD_D5 >>> PORTE 13
    - LCD_D6 >>> PORTE 11
    - LCD_D7 >>> PORTE 12
    - LCD_RS >>> PORTE 8
    - LCD_RW >>> PORTE 7
    - LCD_EN >>> PORTE 10
Terus terang, library ini bukan buatan saya sendiri, tapi saya copy dari hasil searching di internet, dan saya juga lupa dari mana saya mendapatkanya, berhubung banyaknya library LCD yang saya coba. Tapi berikut library yang saya peroleh:

//******************************************************************************
//    THE SOFTWARE INCLUDED IN THIS FILE IS FOR GUIDANCE ONLY.
//    AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT
//    OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
//    FROM USE OF THIS SOFTWARE.
//******************************************************************************

//##############################################################################
// simpan file ini dengan nama hd44780.h
//##############################################################################

//****************************************************************************//
//#include "main.h"


#define LCD_GPIO GPIOE
#define LCD_CLK_LINE RCC_AHB1Periph_GPIOE

#define LCD_D4 GPIO_Pin_14
#define LCD_D5 GPIO_Pin_13
#define LCD_D6 GPIO_Pin_11
#define LCD_D7 GPIO_Pin_12

#define LCD_RS GPIO_Pin_8
#define LCD_RW GPIO_Pin_7
#define LCD_EN GPIO_Pin_10
//******************************************************************************//


#define HD44780_CLEAR                                          0x01

#define HD44780_HOME                                           0x02

#define HD44780_ENTRY_MODE                            0x04
        #define HD44780_EM_SHIFT_CURSOR          0
        #define HD44780_EM_SHIFT_DISPLAY         1
        #define HD44780_EM_DECREMENT               0
        #define HD44780_EM_INCREMENT               2

#define HD44780_DISPLAY_ONOFF                      0x08
        #define HD44780_DISPLAY_OFF                    0
        #define HD44780_DISPLAY_ON                     4
        #define HD44780_CURSOR_OFF                    0
        #define HD44780_CURSOR_ON                      2
        #define HD44780_CURSOR_NOBLINK          0
        #define HD44780_CURSOR_BLINK               1

#define HD44780_DISPLAY_CURSOR_SHIFT 0x10
        #define HD44780_SHIFT_CURSOR               0
        #define HD44780_SHIFT_DISPLAY              8
        #define HD44780_SHIFT_LEFT                     0
        #define HD44780_SHIFT_RIGHT                  4

#define HD44780_FUNCTION_SET                       0x20
        #define HD44780_FONT5x7                            0
        #define HD44780_FONT5x10                          4
        #define HD44780_ONE_LINE                         0
        #define HD44780_TWO_LINE                         8
        #define HD44780_4_BIT                                  0
        #define HD44780_8_BIT                                  16

#define HD44780_CGRAM_SET                                    0x40

#define HD44780_DDRAM_SET                                    0x80

//##############################################################
void lcd_init(void);
void lcd_cls(void);
void lcd_str(unsigned char * text);
void lcd_strxy(unsigned char * text, unsigned char x, unsigned char y);
void lcd_locate(unsigned char x, unsigned char y);
void lcd_int(int n);
void lcd_intxy(int n, unsigned char x, unsigned char y);
//unsigned char* intToStr(int n); 
//###############################################################

void lcd_writedata(unsigned char dataToWrite);
void lcd_writecommand(unsigned char commandToWrite);
void lcd_writebinary(unsigned int var, unsigned char bitCount);
void lcd_addchar (unsigned char chrNum, unsigned char n, const unsigned char *p);

Sedangkan Source dari library diatas adalah sebagai berikut:

/*simpan file ini dengan naman hd44780.c*/
#include "hd44780.h"
#include "stm32f4xx_gpio.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "stm32f4_discovery.h"

GPIO_InitTypeDef GPIO_InitStructure;

//-----------------------------------------------------------------------------
void lcd_writenibble(unsigned char nibbleToWrite)
{
  GPIO_WriteBit(LCD_GPIO, LCD_EN, Bit_SET);
  GPIO_WriteBit(LCD_GPIO, LCD_D4,(BitAction) (nibbleToWrite & 0x01));
  GPIO_WriteBit(LCD_GPIO, LCD_D5,(BitAction)(nibbleToWrite & 0x02));
  GPIO_WriteBit(LCD_GPIO, LCD_D6,(BitAction)(nibbleToWrite & 0x04));
  GPIO_WriteBit(LCD_GPIO, LCD_D7,(BitAction)(nibbleToWrite & 0x08));
  GPIO_WriteBit(LCD_GPIO, LCD_EN, Bit_RESET);
}
//-----------------------------------------------------------------------------
unsigned char LCD_ReadNibble(void)
{
  unsigned char tmp = 0;
  GPIO_WriteBit(LCD_GPIO, LCD_EN, Bit_SET);
  tmp |= (GPIO_ReadInputDataBit(LCD_GPIO, LCD_D4) << 0);
  tmp |= (GPIO_ReadInputDataBit(LCD_GPIO, LCD_D5) << 1);
  tmp |= (GPIO_ReadInputDataBit(LCD_GPIO, LCD_D6) << 2);
  tmp |= (GPIO_ReadInputDataBit(LCD_GPIO, LCD_D7) << 3);
  GPIO_WriteBit(LCD_GPIO, LCD_EN, Bit_RESET);
  return tmp;
}
//-----------------------------------------------------------------------------
unsigned char LCD_ReadStatus(void)
{
  unsigned char status = 0;

    GPIO_InitStructure.GPIO_Pin   =  LCD_D4 | LCD_D5 | LCD_D6 | LCD_D7;
    GPIO_InitStructure.GPIO_Mode  =  GPIO_Mode_IN;
    GPIO_Init(LCD_GPIO, &GPIO_InitStructure);

    GPIO_WriteBit(LCD_GPIO, LCD_RW, Bit_SET);
    GPIO_WriteBit(LCD_GPIO, LCD_RS, Bit_RESET);

    status |= (LCD_ReadNibble() << 4);
    status |= LCD_ReadNibble();

    GPIO_InitStructure.GPIO_Pin   =  LCD_D4 | LCD_D5 | LCD_D6 | LCD_D7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_Init(LCD_GPIO, &GPIO_InitStructure);

  return status;

//-----------------------------------------------------------------------------
void lcd_writedata(unsigned char dataToWrite)
{
  GPIO_WriteBit(LCD_GPIO, LCD_RW, Bit_RESET);
  GPIO_WriteBit(LCD_GPIO, LCD_RS, Bit_SET);

  lcd_writenibble(dataToWrite >> 4);
  lcd_writenibble(dataToWrite & 0x0F);

  while(LCD_ReadStatus() & 0x80);
}
//-----------------------------------------------------------------------------
void lcd_writecommand(unsigned char commandToWrite)
{
  GPIO_WriteBit(LCD_GPIO, LCD_RW | LCD_RS, Bit_RESET);
  lcd_writenibble(commandToWrite >> 4);
  lcd_writenibble(commandToWrite & 0x0F);

  while(LCD_ReadStatus() & 0x80);
}
//-----------------------------------------------------------------------------
void lcd_str(unsigned char * text)
{
  while(*text)
    lcd_writedata(*text++);

//-----------------------------------------------------------------------------
void lcd_locate(unsigned char x, unsigned char y)
{
  lcd_writecommand(HD44780_DDRAM_SET | (x + (0x40 * y)));
}
//-----------------------------------------------------------------------------
void lcd_strxy(unsigned char * text, unsigned char x, unsigned char y)
{
  lcd_locate(x,y);
  while(*text)
    lcd_writedata(*text++);

//-----------------------------------------------------------------------------
void lcd_writebinary(unsigned int var, unsigned char bitCount)
{
  signed char i;

  for(i = (bitCount - 1); i >= 0; i--)
     {
     lcd_writedata((var & (1 << i))?'1':'0');
     }

//-----------------------------------------------------------------------------
void LCD_ShiftLeft(void)
{
  lcd_writecommand(HD44780_DISPLAY_CURSOR_SHIFT | HD44780_SHIFT_LEFT | HD44780_SHIFT_DISPLAY);
}
//-----------------------------------------------------------------------------
void LCD_ShiftRight(void)
{
  lcd_writecommand(HD44780_DISPLAY_CURSOR_SHIFT | HD44780_SHIFT_RIGHT | HD44780_SHIFT_DISPLAY);
}
//-----------------------------------------------------------------------------
void lcd_init(void)
{
  volatile unsigned char i = 0;
  volatile unsigned int delayCnt = 0;
  RCC_AHB1PeriphClockCmd(LCD_CLK_LINE, ENABLE);
  GPIO_InitStructure.GPIO_Pin = LCD_D4|LCD_D5|LCD_D6|LCD_D7|LCD_RS|LCD_RW|LCD_EN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

  GPIO_Init(LCD_GPIO, &GPIO_InitStructure);

  GPIO_ResetBits(LCD_GPIO, LCD_RS | LCD_EN | LCD_RW);

  for(delayCnt = 0; delayCnt < 300000; delayCnt++);

  for(i = 0; i < 3; i++) {
    lcd_writenibble(0x03);
    for(delayCnt = 0; delayCnt < 30000; delayCnt++);
  }

  lcd_writenibble(0x02);

  for(delayCnt = 0; delayCnt < 6000; delayCnt++);

  lcd_writecommand(HD44780_FUNCTION_SET |
                   HD44780_FONT5x7 |
                   HD44780_TWO_LINE |
                   HD44780_4_BIT);

  lcd_writecommand(HD44780_DISPLAY_ONOFF |
                   HD44780_DISPLAY_OFF);

  lcd_writecommand(HD44780_CLEAR);

  lcd_writecommand(HD44780_ENTRY_MODE |
                   HD44780_EM_SHIFT_CURSOR |
                   HD44780_EM_INCREMENT);

  lcd_writecommand(HD44780_DISPLAY_ONOFF |
                   HD44780_DISPLAY_ON |
                   HD44780_CURSOR_OFF |
                   HD44780_CURSOR_NOBLINK);
}
//-----------------------------------------------------------------------------
void lcd_addchar (unsigned char chrNum, unsigned char n, const unsigned char *p)
{
        lcd_writecommand(HD44780_CGRAM_SET | chrNum * 8);
        n *= 8;
        do
                lcd_writedata(*p++);
        while (--n);

//-----------------------------------------------------------------------------
void lcd_cls(void){
        lcd_writecommand(HD44780_CLEAR);
}

unsigned char* intToStr(int n)
{
     int i = 0;
     int j = 0;
   char *tmp = (char*)malloc(sizeof(char));
     unsigned char *ret = (unsigned char*)malloc(12);
   if(n<0 font="">
 *tmp = n%10+48;
 n-=n%10;
 n/=10;
 tmp++;
 i++;
}
*tmp = n+48;
i++;
while(i--){
 ret[j++] = *tmp--;
}
return ret;
}
void lcd_int(int a){
 unsigned short ch,first; //you need this to display 0 if there was any char

    //Get first char
    ch = a/10000;
    if(ch){
     lcd_writedata(48+ch);
     first = 1;
    }

    //Get second char
    ch = (a/1000)%10;
    if(ch || first){
     lcd_writedata(48+ch);
     first = 1;
    }

    //Get third char
    ch = (a/100)%10;
    if(ch || first){
     lcd_writedata(48+ch);
     first = 1;
    }

    //Get fourth char
    ch = (a/10)%10;
    if(ch || first){
     lcd_writedata(48+ch);
     //first = 1;                   //q
    }

    //Get fifth char
    ch = a%10;
    //if(ch || first)   //you dont need to check las one if ch is 0 then just display it, unless you dont want to then uncomment this line ("//q" line too)
     lcd_writedata(48+ch);
       // lcd_str(intToStr(n));
}

void lcd_intxy(int n, unsigned char x, unsigned char y)
{
        lcd_locate(x,y);
        lcd_int(n);
}

Dari sekian banyaknya fungsi, saya cuman baru make beberapa fungsi saja. Yang ditampilkan di postingan ini hanya untuk menampilkan karakter sdan string ke LCD saja. Pelan pelan saja, jangan buru buru. hehehe
Berikut Fungsi main.c dari project yang saya buat:

#include
#include
#include
#include
#include

int main(void)
{
  lcd_init(); 
  lcd_cls();
  lcd_strxy("_ardiansm",0,0);
  lcd_strxy("CircuitDrilling",0,1);
}

Sudah dulu ya, cukup begitu saja. Barangkali ada yang punya pikiran, kenapa g dijelasin proses komunikasi data antara LCD dan board STM32F4 nya. Karena saya punya pikiran, LCD 16x2 ini sudah banyak sekali yang membahas, dan sebagian besar aplikasi LCD ini hanya untuk display, hanya penting pada beberapa aplikasi HMI saja. Dan lagi pula, kebanyakan orang juga jarang ada yang mau baca detail komunikasinya, cukup copy paste library, udah deh selasai.


Ditunggu komen dan kritiknya yak.

Senin, 10 Februari 2014

Membuat project baru pada Keil uVision untuk pemrograman board STM32F4 Discovery (New Project in uVision STM32F4 Discovery)

Hai hai...kembali lagi bersama saya dengan tampilan blog yang baru dengan nama CircuitDrilling. Apa filosofi dari Circuit Drilling? Bodo amat apalah arti sebuah nama, walau sebenarnya nama juga penting buat marketing. Ok lah, setelah sekian lama vakum dari dunia blogger, sekarang saya kembali lagi exsist dengan tema blog yang lebih specific, yaitu Electronics, Drilling, dan pengalaman perjalanan saya mengarungi kehidupan per-mbolangan.

Postingan terakhir saya sebelum ini adalah tentang pemrograman ARM Cortex M4 dengan menggunakan WinArm, tapi karena alasa kepratisan, maka saya mulai berpindah ke software yang lebih user friendly, yaitu KEIL uVision.


Tidak perlu panjang lebar tentang software ini, yang jelas lebih mudah dari pada WinARM. Tapi dengan konsekwnsi kita harus beli versi berlisensi nya. Tapi untuk Trial, ada juga versi eval nya, kalau mau download silakan di www.keil.com , atau untuk versi gratisan yang tidak resmi alias crack2an, silakan saja cari 4shared atau tempat lain, tang jelas banyak yang makai IDE ini kok.

Setelah diinstal dan dibaca readme nya, tampilan uVision adalah sebagai berikut.



Bingung kan, kok kosong melompong. hahaha. Software ini berbeda dengan software yang biasa saya gunakan untuk pemrograman microcontroller AVR ATMega family, yaitu CodeVision AVR, yang dimana CV AVR mempunyai code wizard yang akan menggenerate coding secara otomatis. Di uVision, tidak disediakan fasilitas seperti itu. Kenapa? tak taulah awak, tapi yang jelas menurut awak, yang namanya codewizaerd itu adalah fasilitas PEMBODOHAN (hahaha), walau memang bisa dibilang sangat praktis.

Ada yang lupa saudara, sebelum membuat project baru, sangat saya sarankan untuk mendownload file file update dari UVision yang bisa di download disini , file tersebut berisi library library  yang  kita perlukan selain library asli dari software uVision nya.

Langsung saja, untuk membuat project baru, kita klik tab Project  > New uVision Project , maka akan keluar pop up yang meminta kita untuk menentukan tempat kita menaruh file project kita. Di laptop awak, akan saya coba untuk menyimpanya di drive D:/arm_dev , tapi kalo ente terserah. Beri nama yang mudah diingat sesui dengan tema project yang kita buat, project kita akan otomatis disimapn dengan ekstensi .uvproj. Kemudian klik Save. kemuadian akan muncul tampilan seperti ini :


Pop up tersebut digunakan untuk memilih tipe dari processor apa yang kita pakai. Berhubung saya memakai board STM32F4 Discovery, maka saya akan memilih STMicroelectronics >> STM32F407VG. Klik ok, dan kemudian akan muncul pertanyaan 'Copy 'startup_stm32f4xx.s' to Project Folder and Add File to Project?'? Yes, saya sangat ingin sekali menambahkan file penting tersebut. File tersebut digunakan sebagai parameter parameter dari chip yang kita pakai.

Akhirnya kita masuk ke project baru, tapi kok tetep kosong. Hahaha. Di uVision, kita benar benar membuat pemrograman dari nol, saran saya, untuk membuat pemrograman STM32F4 lebih cepat, siap siap dengan senjata Copy-Paste. Di window tersebut kita sudah melihat Target1, yaitu project sasaran eksekusi dari compiler maupun linker dan lain lain. Yang perlu kita lakukan sekarang adalah, kita perlu menambahkan sedikit setingan pada Target Options. Klik tap Projects >> Option for Target 'nama target' ( atau icon yang ada tongkat penyihir-nya), maka akan keluar popup seperti ini:


Di tab tersebut, ada yang perlu kita sesuaikan, antara lain:  
1. XTal (MHz) = 8.00 MHz (sesuai dengan xtal dari board, sebenarnya bisa di optimalkan sampe 160an MHz, tipa kita bahas nanti)
2. Centang Use MicroLIB
3. Centang IRAM2

Di tab Output, jangan lupa dicentang Create Hex File

Di tab C/C++, perlu banyak setingan. Bisa dilihat di bawah ini:
1. Define = USE_STDPERIPH_DRIVER , STM32F4XX
2. Optimation : Level 3
3. Centang One ELF Section per Function
4. Include path, lebih mudah untuk ditunjukkan dengan gambar. hahaha:


PERHATIAN : Di awal tadi, saya anggap ente ente sudah mendownload file library dari website ST, atau bila belum download silakan klik disini. Bila sudah, extrak file tersebut di sebuah folder yang tidak terlalu "dalam". maksudnya, kalau bisa di extrak di folder di drive D ata C, jangan dimasukin ke folder folder lagi. Semua folder yang terdapat pada include path tab, diambil dari hasil extrak file yang di download. 

Di tab ASM, selalu saya isi Define = USE_STDPERIPH_DRIVER , STM32F4XX

Di tab Debug, lihat saja gambar ini. ST-Link Debugger dipilih karena saya menggunakan debugger bawaan dari board STM32f4 Discovery.



Di tab Utilities , silakan saja liat gambar. hehehe


Oh iya ada 1 lagi yang lupa. Berdasarkan pengalaman, lebih baik copy stm32f4xx_syscfg.c dan system_stm32f4xx.c  ke folder dari project kita. File tersebut bisa dicopy file kita download sebelumnya (di folder src).

Ok, sekarang mari kita buat project sederhana di sini. Kita bisa saja buka example yang ada, tapi ngga greget kalo g bikin sendiri kan. Di sini kita buat aplikasi sederhana yang melibatkan I/O dari board STM32F4 Discovery. Pergi ke tab FILE >> New .Biar g lama, silakan copy saja file dibawah ini dan paste ke file baru tersebut.

#include // library setting I/O
#include //library pengaturan clock
#include

volatile char btns;

void Delay(__IO uint32_t nCount)
{
  while(nCount--)
  {
/*Fungsi delay ini tidak presisi karena menggunakan metode TEKIRO alias teknik kiro kiro*/
uint32_t i;
for (i=0;i<42000 i="">
{}
i=0;
  }
}

void BTN_Init(void) 
{
/*user push button terhubung dengan PA.0*/
  RCC->AHB1ENR  |= ((1UL <<  0) );              /* Enable GPIOA clock         */

  GPIOA->MODER    &= ~((3UL <<; 2*0)  );         /* PA.0 is input              */
  GPIOA->OSPEEDR  &= ~((3UL << 2*0)  );         /* PA.0 is 50MHz Fast Speed   */
  GPIOA->OSPEEDR  |=  ((2UL << 2*0)  ); 
  GPIOA->PUPDR    &= ~((3UL << 2*0)  );         /* PA.0 is no Pull up         */
}
uint32_t BTN_Get(void) 
{
 return (GPIOA->IDR & (1UL << 0)); //cek nilai dari register IDR PA.0
}
void LED_Init(void)
{
/*LED terhubung ke PD.12, PD.13, PD.14, PD.15 */
RCC->AHB1ENR  |= ((1UL << 3) );         /* Enable GPIO port D clock                */
GPIOD->MODER    &= ~((3UL << 2*12) |
                       (3UL << 2*13) |
                       (3UL << 2*14) |
                       (3UL << 2*15)  );   /* PD.12..15 is output               */
  GPIOD->MODER    |=  ((1UL << 2*12) |
                       (1UL << 2*13) | 
                       (1UL << 2*14) | 
                       (1UL << 2*15)  ); 
  GPIOD->OTYPER   &= ~((1UL <<   12) |
                       (1UL <<   13) |
                       (1UL <<   14) |
                       (1UL <<   15)  );   /* PD.12..15 is output Push-Pull     */
GPIOD->OSPEEDR  &= ~((3UL << 2*12) |
                       (3UL << 2*13) |
                       (3UL << 2*14) |
                       (3UL << 2*15)  );   /* PD.12..15 is 50MHz Fast Speed     */
  GPIOD->OSPEEDR  |=  ((2UL << 2*12) |
                       (2UL << 2*13) | 
                       (2UL << 2*14) | 
                       (2UL << 2*15)  ); 
GPIOD->PUPDR    &= ~((3UL << 2*12) |
                       (3UL << 2*13) |
                       (3UL << 2*14) |
                       (3UL << 2*15)  );   /* PD.12..15 is Pull up              */
  GPIOD->PUPDR    |=  ((1UL << 2*12) |
                       (1UL << 2*13) | 
                       (1UL << 2*14) | 
                       (1UL << 2*15)  );  
}

int main(void)
{
/*
Fungis ini merupakan contoh sederhana dari STM32F4 Discovery. Jika user button ditekan, maka LED3, LED4, LED5, LED6 akan mati,
dan jika dilepas, LED3, LED4, LED5, LED6 akan menyala.
*/
  // Systemclock auf 168MHz (stm32F4Discovery mit 8MHz Quarz)
  SystemInit();
//INIT BUTTON AND LEDS
BTN_Init();
LED_Init();
while(1)
    {
   
btns = BTN_Get();
if(btns ==(1UL << 0))
{
btns=0;
GPIOD->BSRRH = 1UL << 12; GPIOD->BSRRH = 1UL << 13; GPIOD->BSRRH = 1UL << 14;GPIOD->BSRRH = 1UL << 15;
Delay(1000);
}
else
{
GPIOD->BSRRL = 1UL << 12; GPIOD<<BSRRL = 1UL << 13; GPIOD->BSRRL = 1UL << 14;GPIOD->BSRRL = 1UL << 15;
}
    }
}

Kemudian simpan dengan nama main.c di folder project kita. Kita juga perlu menambahkan beberapa file source ke dalam target atau project kita. Untuk memudahkan dalam proses pengenalan file, lebih baik kita pisahkan file ke beberapa group. Cara membuat adalah dengan cara klik kanan Target1 >> Add Group. Kita beri nama group baru tersebut dengan nama source dan source2. Kemudian tambahkan file ke dalam group dengan cara klik kanan nama group, misal source2 >> Add files to group 'source2'. Hasil dari penambahan file ke project adalah seperti gambar di bawah ini.



Setelah semua project di compile dan di built dengan tanpa menghasilkan error, maka project kita sipa untuk di Load ke board STM32F4 kita.

Cukup kayaknya tulisan ini. Mungkin ada beberapa orang yang baca tulisan ini berpikir "RIbet amat ya". Kalau misal ada yang punya cara lebih bagus, tolong di share di mari ya, kan sama sama belajarnya :D