洪嵐峰 發表於 2023-4-17 20:30:56

PIC18F46K22微控制器

所需的零件清單、示例程式碼:

所需零件:

PIC18F46K22 微控制器
16MHz 晶振
22pF 綠色陶瓷電容 x2
10k 歐姆電阻 x2
10uF 25V 電解電容
1N4001 阻擋二極管
LED x2
220 歐姆電阻 x2
2x20 腳 LCD 顯示器
10k 歐姆可變電阻
按鈕開關 x4
杜邦線、面包板等
連接腳位:


   PIC18F46K22
   +---------+
   |         |
VSS|1       40|VDD
RA0|2       39|PGC
RA1|3       38|PGD
RA2|4       37|VSS
RA3|5       36|OSC1
RA4|6       35|OSC2
RA5|7       34|AN11
RC0|8       33|AN10
RC1|9       32|AN9
RC2|10      31|AN8
RC3|11      30|AN7
RC4|12      29|AN6
RC5|13      28|AN5
RC6|14      27|AN4
RC7|15      26|AN3
   |         |
   +---------+
示例程式碼:


#include <xc.h>

#pragma config FOSC = INTIO67   // 內部振盪器
#pragma config PLLCFG = ON      // PLL 開啟
#pragma config PRICLKEN = OFF   // 主時鐘開啟
#pragma config PWRTEN = ON      // 電源上電延遲
#pragma config BOREN = OFF      // 無須 Brown-out 检测
#pragma config BORV = 190       // Brown-out 電壓設為 1.9V
#pragma config WDTEN = OFF      // 看門狗定時器關閉
#pragma config CCP2MX = PORTC   // CCP2 輸出映射到 C3

#define _XTAL_FREQ 16000000     // 頻率 16MHz

void main() {
   // 設置 GPIO 方向
   TRISC = 0b00000000;         // C 腳位設置為輸出模式
   LATC = 0b00000000;          // 將 C 腳位拉低

   // 初始化 LCD 顯示器
   lcd_init();

   // 顯示訊息
   lcd_puts("Hello World!");

   while (1) {
      // 讀取按鈕開關狀態
     
  if (PORTAbits.RA0 == 1) {   // 如果按鈕1被按下
     LATCbits.LC0 = 1;        // C0 腳位為高電位,LED亮
     lcd_clear();             // 清空 LCD 顯示器
     lcd_puts("Button 1");    // 顯示訊息
  } else {
     LATCbits.LC0 = 0;        // C0 腳位為低電位,LED滅
  }

  if (PORTAbits.RA1 == 1) {   // 如果按鈕2被按下
     LATCbits.LC1 = 1;        // C1 腳位為高電位,LED亮
     lcd_clear();             // 清空 LCD 顯示器
     lcd_puts("Button 2");    // 顯示訊息
  } else {
     LATCbits.LC1 = 0;        // C1 腳位為低電位,LED滅
  }

  if (PORTAbits.RA2 == 1) {   // 如果按鈕3被按下
     LATCbits.LC2 = 1;        // C2 腳位為高電位,LED亮
     lcd_clear();             // 清空 LCD 顯示器
     lcd_puts("Button 3");    // 顯示訊息
  } else {
     LATCbits.LC2 = 0;        // C2 腳位為低電位,LED滅
  }

  if (PORTAbits.RA3 == 1) {   // 如果按鈕4被按下
     LATCbits.LC3 = 1;        // C3 腳位為高電位,LED亮
     lcd_clear();             // 清空 LCD 顯示器
     lcd_puts("Button 4");    // 顯示訊息
  } else {
     LATCbits.LC3 = 0;        // C3 腳位為低電位,LED滅
  }
}
}

// 初始化 LCD 顯示器
void lcd_init() {
// 設置 LCD 顯示器腳位為輸出模式
TRISD = 0b00000000;

// 初始設置
LATD = 0b00110000;
__delay_ms(10);
LATD = 0b00110000;
__delay_ms(10);
LATD = 0b00110000;
__delay_ms(10);
LATD = 0b00100000;
__delay_ms(10);
lcd_cmd(0b00101000); // 4 位元、2 行、5x8 點
lcd_cmd(0b00001000); // 顯示器和游標關閉
lcd_cmd(0b00000001); // 顯示器清屏
lcd_cmd(0b00000110); // 游標右移
lcd_cmd(0b00001100); // 顯示

// 寫入指令到 LCD 顯示器
void lcd_cmd(unsigned char cmd) {
LATD = (cmd >> 4) & 0x0F; // 寫入高位元
LATDbits.LD7 = 0; // RS 腳位為低電位,選擇指令模式
LATDbits.LD6 = 0; // RW 腳位為低電位,選擇寫入模式
LATDbits.LD5 = 1; // E 腳位為高電位,啟動 LCD 顯示器

__delay_us(10); // 等待一段時間

LATDbits.LD5 = 0; // E 腳位為低電位,關閉 LCD 顯示器
__delay_us(10); // 等待一段時間

LATD = cmd & 0x0F; // 寫入低位元
LATDbits.LD5 = 1; // E 腳位為高電位,啟動 LCD 顯示器

__delay_us(10); // 等待一段時間

LATDbits.LD5 = 0; // E 腳位為低電位,關閉 LCD 顯示器
__delay_ms(5); // 等待一段時間
}

// 寫入字元到 LCD 顯示器
void lcd_putc(unsigned char c) {
LATD = (c >> 4) & 0x0F; // 寫入高位元
LATDbits.LD7 = 1; // RS 腳位為高電位,選擇資料模式
LATDbits.LD6 = 0; // RW 腳位為低電位,選擇寫入模式
LATDbits.LD5 = 1; // E 腳位為高電位,啟動 LCD 顯示器

__delay_us(10); // 等待一段時間

LATDbits.LD5 = 0; // E 腳位為低電位,關閉 LCD 顯示器
__delay_us(10); // 等待一段時間

LATD = c & 0x0F; // 寫入低位元
LATDbits.LD5 = 1; // E 腳位為高電位,啟動 LCD 顯示器

__delay_us(10); // 等待一段時間

LATDbits.LD5 = 0; // E 腳位為低電位,關閉 LCD 顯示器
__delay_ms(5); // 等待一段時間
}

// 寫入字串到 LCD 顯示器
void lcd_puts(const char* s) {
while (*s) {
lcd_putc(*s++);
}
}

// 主程式
void main(void) {
// 設定 I/O 腳位
TRISD = 0x00; // 設定 PORTD 為輸出
TRISEbits.RE0 = 1; // 設定 RE0 為輸入
ANSELEbits.ANSE0 = 0; // 設定 RE0 為數位腳位

// 初始化 LCD 顯示器
lcd_init();

while (1) {
// 讀取 RE0 腳位的狀態
if (PORTEbits.RE0 == 1) {
lcd_cmd(0x01); // 清除顯示器
lcd_puts("Button Pressed");
} else {
lcd_cmd(0x01); // 清除顯示器
lcd_puts("Button Not Pressed");
}

scss
Copy code
  __delay_ms(500);           // 等待一段時間
}
}

// 函式:LCD 初始化
void lcd_init(void) {
lcd_cmd(0x02); // 回到 Home 狀態
lcd_cmd(0x28); // 設定 4-bit 模式,2 行顯示,5x7 字元大小
lcd_cmd(0x0C); // 顯示器 ON,游標不閃爍
lcd_cmd(0x06); // 游標右移
lcd_cmd(0x01); // 清除顯示器
__delay_ms(2); // 等待 LCD 完成命令
}

// 函式:傳送命令到 LCD
void lcd_cmd(unsigned char command) {
// 傳送上半個 Byte
PORTD &= 0x0F; // 清除上半個 Byte
PORTD |= (command & 0xF0); // 寫入上半個 Byte
PORTDbits.RD2 = 0; // RS 腳位設為命令模式
PORTDbits.RD3 = 1; // 使能腳位設為高
__delay_us(1); // 等待一段時間
PORTDbits.RD3 = 0; // 使能腳位設為低
__delay_us(100); // 等待一段時間

// 傳送下半個 Byte
PORTD &= 0x0F; // 清除上半個 Byte
PORTD |= ((command << 4) & 0xF0); // 寫入下半個 Byte
PORTDbits.RD2 = 0; // RS 腳位設為命令模式
PORTDbits.RD3 = 1; // 使能腳位設為高
__delay_us(1); // 等待一段時間
PORTDbits.RD3 = 0; // 使能腳位設為低
__delay_us(100); // 等待一段時間
}

// 函式:傳送資料到 LCD
void lcd_putc(unsigned char data) {
// 傳送上半個 Byte
PORTD &= 0x0F; // 清除上半個 Byte
PORTD |= (data & 0xF0); // 寫入上半個 Byte
PORTDbits.RD2 = 1; // RS 腳位設為資料模式
PORTDbits.RD3 = 1; // 使能腳位設為高
__delay_us(1); // 等待一段時間
PORTDbits.RD3 = 0; // 使能腳位設為低
__delay_us(100); // 等待一段時間

// 傳送下半個 Byte
PORTD &= 0x0F; // 清除
PORTD |= ((data << 4) & 0xF0); // 寫入下半個 Byte
PORTDbits.RD2 = 1; // RS 腳位設為資料模式
PORTDbits.RD3 = 1; // 使能腳位設為高
__delay_us(1); // 等待一段時間
PORTDbits.RD3 = 0; // 使能腳位設為低
__delay_us(100); // 等待一段時間
}

// 函式:設定游標位置
void lcd_set_cursor(unsigned char row, unsigned char col) {
// 計算游標位置
unsigned char pos;
if (row == 1) {
pos = 0x80 + col - 1;
} else if (row == 2) {
pos = 0xC0 + col - 1;
} else if (row == 3) {
pos = 0x94 + col - 1;
} else if (row == 4) {
pos = 0xD4 + col - 1;
}

// 傳送設定命令
lcd_cmd(pos);
}

// 函式:顯示字串
void lcd_puts(unsigned char row, unsigned char col, const char *str) {
lcd_set_cursor(row, col); // 設定游標位置

// 逐一顯示字元
while (*str != '\0') {
lcd_putc(*str++);
}
}

// 主程式
void main() {
// 初始化 LCD
lcd_init();

// 顯示文字
lcd_puts(1, 1, "Hello World!");
}


以上就是一個簡單的 LCD 顯示程式,可以顯示「Hello World!」字串在 LCD 上。
頁: [1]
查看完整版本: PIC18F46K22微控制器