5Vだしパラレル入力だし・・・。
最近では、3VとかI2C通信のものが安価に出ている。
困った。 FON2405E(Linuxボード)は 3Vだし、今のところSPIしか使えていない。
そこで、PICマイコン使って
- インターフェース変換(SPI to パラレル)
- 3V駆動
- SW入力
- バックライト
先に結論↓ こんな感じで、Linuxボードから制御してみた。
1. インターフェース変換
SPI搭載の手持ちPICマイコン=PIC16F818 / 819 にした。
まぁシフトレジスタでも実現できるような気がするけど。
http://www.aitendo.com/product/14623
だけど3V駆動化とかSW入力とかやりたいので、今回はPICにこだわった。
2. 3V駆動
いろいろな方が実現している。感謝!
PICにてPWM出力し、チャージポンプにて負電圧を生成する。
最初に思いついた方すごいね!
http://elm-chan.org/docs/lcd/lcd3v_j.html
http://jsdiy.web.fc2.com/lcd3v/
3. SW入力
入力ピンが足りないので、アナログ入力+抵抗分圧にて。
こちらもいろいろな方が実現している。感謝。
https://synapse.kyoto/hard/keypad/page001.html
4. バックライト
バックライト駆動するためには4V 40mA程度必要っぽい。
2のチャージポンプでは賄えないか・・・。
要検討・・・。
んでもって、現状の回路図はこんな感じ。
ソースコード
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* File: lcd_lib.c | |
* Author: adeno | |
* | |
* Created on 2018/06/25, 1:18 | |
*/ | |
#include <xc.h> | |
#include "lcd_lib.h" | |
/* | |
* | |
*/ | |
void lcd_change_col(unsigned char i){ | |
// if(i == 1) { lcd_cmd(0xC0); } | |
// else {lcd_cmd(0x80);} | |
if(i == 1){ | |
lcd_out(0xC0,0); | |
lcd_out(0x00,0); //<<4 | |
}else{ | |
lcd_out(0x80,0); | |
lcd_out(0x00,0); //<<4 | |
} | |
__delay_ms(2); | |
} | |
/// | |
///LCDにコマンド・文字を出力 | |
/// charflg=0 コマンド、charflg=1 文字 | |
/// 要指定 | |
/// #define lcd_e_bit | |
/// #define lcd_rs_bit | |
/// #define lcd_port PORTA この場合、RA3 - 0を使う | |
void lcd_out(unsigned char code,unsigned char charflg){ | |
unsigned char port_bak; | |
unsigned char rs_bit = (1 << lcd_rs_bit); | |
unsigned char e_bit = (1 << lcd_e_bit); | |
//データ出力 | |
port_bak = lcd_port & 0b11100001; //RA4 - 1 | |
port_bak = port_bak | (0b00011110 & (code >> 3)); | |
lcd_port = port_bak; | |
//rs set | |
port_bak = port_bak & (~rs_bit); | |
if (charflg == 1){ | |
//RSをhigh | |
port_bak = port_bak | rs_bit; | |
} | |
lcd_port = port_bak; | |
//eにワンショット | |
port_bak = port_bak & (~e_bit); | |
lcd_port = port_bak | e_bit; | |
__nop(); | |
lcd_port = port_bak; | |
} | |
void lcd_clear(){ | |
lcd_cmd(0x01); | |
__delay_ms(15); | |
} | |
void lcd_init(){ | |
//LCDの初期化 | |
__delay_ms(15); | |
lcd_out(0x30,0); | |
__delay_ms(5); | |
lcd_out(0x30,0); | |
__delay_ms(1); | |
lcd_out(0x30,0); | |
__delay_ms(1); | |
lcd_out(0x20,0); | |
__delay_ms(1); | |
lcd_cmd(0x2e); | |
// lcd_out(0x2e,0); | |
// lcd_out(0xe0,0); //<<4 | |
// __delay_ms(2); | |
lcd_cmd(0x08); | |
lcd_cmd(0x0d); | |
lcd_cmd(0x06); | |
lcd_cmd(0x02); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* File: lcd_lib.h | |
* Author: adeno | |
* | |
* Created on 2018/06/25, 1:20 | |
*/ | |
#ifndef LCD_LIB_H | |
#define LCD_LIB_H | |
#ifdef __cplusplus | |
extern "C" { | |
#endif | |
//出力にラッチがないPIC向けで、データと制御のポート群が同じ場合 | |
//データ出力がRx4〜Rx1の場合 | |
#define _XTAL_FREQ 8000000 //delay用に必要(クロック8MHzを指定) | |
//RA1 D4 | |
//RA2 D5 | |
//RA3 D6 | |
//RA4 D7 | |
//RA4 E | |
//RA6 RS | |
#define LCD_ROW 16 | |
#define LCD_COL 2 | |
#define lcd_port PORTA | |
#define lcd_e_bit 7 | |
#define lcd_rs_bit 6 | |
#define lcd_data(ascii) lcd_out(ascii,1);lcd_out(ascii << 4,1);__delay_us(50); | |
#define lcd_cmd(cmd) lcd_out(cmd,0);lcd_out(cmd << 4,0);__delay_ms(2); | |
void lcd_change_col(unsigned char i); | |
void lcd_out(unsigned char code,unsigned char charflg); | |
void lcd_init(); | |
void lcd_clear(); | |
#ifdef __cplusplus | |
} | |
#endif | |
#endif /* LCD_LIB_H */ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* File: main.c | |
* Author: adeno | |
* | |
* Created on 2018/06/05, 3:25 | |
*/ | |
// CONFIG | |
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTRC oscillator; port I/O function on both RA6/OSC2/CLKO pin and RA7/OSC1/CLKI pin) | |
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) | |
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled) | |
#pragma config MCLRE = ON // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR) | |
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled) | |
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB3/PGM pin has digital I/O function, HV on MCLR must be used for programming) | |
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Code protection off) | |
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off) | |
#pragma config CCPMX = RB3 // CCP1 Pin Selection bit (CCP1 function on RB3) | |
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off) | |
// #pragma config statements should precede project file includes. | |
// Use project enums instead of #define for ON and OFF. | |
#include <xc.h> | |
//#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include "lcd_lib.h" | |
__EEPROM_DATA('S','p','i','C','h','a','r','L'); | |
__EEPROM_DATA('C','D',' ','v','0','.','4',' '); | |
//PWM設定(16-) | |
__EEPROM_DATA(0b01,166, 83,0,1,0,0,0); //16 {0b01,166, 83,0,1}, //3kHz | |
__EEPROM_DATA(0b01,199,100,0,0,0,0,0); //24 {0b01,199,100,0,0}, //2.5kHz | |
__EEPROM_DATA(0b01,249,125,0,0,0,0,0); //32 {0b01,249,125,0,0}, //2kHz | |
__EEPROM_DATA(0b10, 82, 42,1,0,0,0,0); //40 {0b10, 82, 42,1,0}, //1.5kHz | |
__EEPROM_DATA(0b10,124, 62,1,0,0,0,0); //48 {0b10,124, 62,1,0}, //1kHz | |
__EEPROM_DATA(0b10,138, 69,0,1,0,0,0); //56 {0b10,138, 69,0,1}, //0.9kHz | |
__EEPROM_DATA(0b10,155, 78,0,0,0,0,0); //64 {0b10,155, 78,0,0}, //0.8kHz | |
void initPWM(void); | |
//void changePWMindex(unsigned char i); | |
//void changePWM(int ps,int pr,int duty,int d1y,int d1x); | |
void changePWMeepromindex(unsigned char i); | |
void initLCD(void); | |
void initAD(void); | |
void initSPI(void); | |
void initTMR0(void); | |
unsigned char getAD(); | |
#define RBUFSIZE 32 | |
#define RBUFMASK 0x1f | |
#define RCV_STATE_FUNC 0 | |
#define RCV_STATE_CPWM 1 | |
#define RCV_STATE_CCMD 2 | |
#define RCV_STATE_CDATA 3 | |
#define RCV_CMD_BKLIGHT 0x00 | |
#define RCV_CMD_PWM 0x01 | |
#define RCV_CMD_LCDCMD 0x02 | |
#define RCV_CMD_LCDDATA 0x03 | |
#define RCV_CMD_SW 0x04 | |
#define RCV_CMD_LCDDATAFIN 0x00 | |
#define RCV_DATA_PWM_0 16 | |
#define RCV_DATA_PWM_1 24 | |
#define RCV_DATA_PWM_2 32 | |
#define RCV_DATA_PWM_3 40 | |
#define RCV_DATA_PWM_4 48 | |
#define RCV_DATA_PWM_5 56 | |
#define RCV_DATA_PWM_6 64 | |
#define GTIMER 131 | |
unsigned char ringbuf[RBUFSIZE]; | |
unsigned char wpoi = 0; | |
unsigned char rpoi = 0; | |
unsigned char rcvstate = 0; | |
unsigned char swadcflg = 0; | |
//struct pwmsetting { | |
// unsigned char ps; | |
// unsigned char pr; | |
// unsigned char duty; | |
// bool d1y; | |
// bool d1x; | |
//}; | |
//struct pwmsetting pwmary[7] = { | |
// //ps, pr, duty, d1y, d1x | |
// {0b01,166, 83,0,1}, //3kHz | |
// {0b01,199,100,0,0}, //2.5kHz | |
// {0b01,249,125,0,0}, //2kHz | |
// {0b10, 82, 42,1,0}, //1.5kHz | |
// {0b10,124, 62,1,0}, //1kHz | |
// {0b10,138, 69,0,1}, //0.9kHz | |
// {0b10,155, 78,0,0}, //0.8kHz | |
// }; | |
void putch(unsigned char c){ | |
lcd_data(c); | |
return; | |
} | |
/* | |
* | |
*/ | |
int main(/*int argc, char** argv*/) { | |
OSCCONbits.IRCF = 0b111; //8MHz | |
initPWM(); | |
initAD(); | |
initSPI(); | |
initLCD(); | |
initTMR0(); | |
unsigned char adv; | |
// unsigned char i; | |
unsigned char oldsw = 0; | |
unsigned char sw = 0; | |
lcd_change_col(1); | |
TMR0 = GTIMER; | |
INTCONbits.TMR0IE = 1; | |
while(1){ | |
if(swadcflg == 1){ | |
swadcflg = 0; | |
adv = getAD(); | |
if(adv > 21 && adv < 26){ | |
//SW1 | |
sw = 1; | |
}else if(adv > 54 && adv < 64){ | |
//SW2 | |
sw = 2; | |
}else if(adv > 105 && adv < 118){ | |
//SW3 | |
sw = 3; | |
}else if(adv > 157 && adv < 170){ | |
//SW4 | |
sw = 4; | |
}else if(adv > 210 && adv < 218){ | |
//SW5 | |
sw = 5; | |
}else if(adv > 238 && adv < 242){ | |
//SW6 | |
sw = 6; | |
}else{ | |
sw = 0; | |
} | |
if(sw != oldsw){ | |
lcd_data(sw+'0'); | |
} | |
oldsw = sw; | |
} | |
// __delay_ms(1); | |
if(wpoi != rpoi){ | |
if(rcvstate == RCV_STATE_FUNC){ | |
if(ringbuf[rpoi] == RCV_CMD_PWM) { rcvstate = RCV_STATE_CPWM; } | |
else if(ringbuf[rpoi] == RCV_CMD_LCDDATA) { rcvstate = RCV_STATE_CDATA; } | |
else if(ringbuf[rpoi] == RCV_CMD_LCDCMD) { rcvstate = RCV_STATE_CCMD; } | |
}else if(rcvstate == RCV_STATE_CPWM){ | |
sw = 0; | |
if(ringbuf[rpoi] == 0) { sw = RCV_DATA_PWM_0;} | |
else if(ringbuf[rpoi] == 1) { sw = RCV_DATA_PWM_1;} | |
else if(ringbuf[rpoi] == 2) { sw = RCV_DATA_PWM_2;} | |
else if(ringbuf[rpoi] == 3) { sw = RCV_DATA_PWM_3;} | |
else if(ringbuf[rpoi] == 4) { sw = RCV_DATA_PWM_4;} | |
else if(ringbuf[rpoi] == 5) { sw = RCV_DATA_PWM_5;} | |
else if(ringbuf[rpoi] == 6) { sw = RCV_DATA_PWM_6;} | |
changePWMeepromindex(sw); | |
rcvstate = RCV_STATE_FUNC; | |
}else if(rcvstate == RCV_STATE_CCMD){ | |
lcd_cmd(ringbuf[rpoi]); | |
rcvstate = RCV_STATE_FUNC; | |
// if(ringbuf[rpoi] == RCV_CMD_LCDDATAFIN) { rcvstate = RCV_STATE_FUNC;} | |
// else{lcd_cmd(ringbuf[rpoi]);} | |
}else if(rcvstate == RCV_STATE_CDATA){ | |
lcd_data(ringbuf[rpoi]); | |
rcvstate = RCV_STATE_FUNC; | |
// if(ringbuf[rpoi] == RCV_CMD_LCDDATAFIN) { rcvstate = RCV_STATE_FUNC;} | |
// else{lcd_data(ringbuf[rpoi]);} | |
} | |
rpoi = (rpoi+1) & RBUFMASK; | |
} | |
// | |
// __delay_ms(2000); | |
// changePWMindex(0); | |
// lcd_change_col(1); | |
// // 0123456789ABCDEF | |
// printf("PWM> 3kHz "); | |
// | |
// __delay_ms(2000); | |
// changePWMindex(1); | |
// lcd_change_col(1); | |
// // 0123456789ABCDEF | |
// printf("PWM> 2.5kHz "); | |
// | |
// for(i=0;i<100;i++){ | |
// __delay_ms(200); | |
// adv = getAD(); | |
// lcd_change_col(1); | |
// printf("AD> %d ",adv); | |
// } | |
// | |
// __delay_ms(2000); | |
// changePWMindex(2); | |
// lcd_change_col(1); | |
// // 0123456789ABCDEF | |
// printf("PWM> 2kHz "); | |
// | |
// __delay_ms(2000); | |
// changePWMindex(3); | |
// lcd_change_col(1); | |
// // 0123456789ABCDEF | |
// printf("PWM> 1.5kHz "); | |
// | |
//// __delay_ms(2000); | |
//// changePWMindex(4); | |
//// lcd_change_col(1); | |
//// // 0123456789ABCDEF | |
//// printf("PWM> 1kHz "); | |
//// | |
//// __delay_ms(2000); | |
//// changePWMindex(5); | |
//// lcd_change_col(1); | |
//// // 0123456789ABCDEF | |
//// printf("PWM> 0.9kHz "); | |
//// | |
//// __delay_ms(2000); | |
//// changePWMindex(6); | |
//// lcd_change_col(1); | |
//// // 0123456789ABCDEF | |
//// printf("PWM> 0.8kHz "); | |
} | |
return (EXIT_SUCCESS); | |
} | |
void initLCD(void){ | |
//RA1 D4 | |
//RA2 D5 | |
//RA3 D6 | |
//RA4 D7 | |
//RA6 RS | |
//RA7 E | |
TRISAbits.TRISA1 = 0; | |
TRISAbits.TRISA2 = 0; | |
TRISAbits.TRISA3 = 0; | |
TRISAbits.TRISA4 = 0; | |
TRISAbits.TRISA6 = 0; | |
TRISAbits.TRISA7 = 0; | |
ADCON1 = 0b1110; //4-1:D 0:A | |
__delay_ms(100); | |
//LCDの初期化 | |
lcd_init(); | |
//LCDの表示クリア | |
lcd_clear(); | |
// dist = DIST_LCD; | |
// 0123456789ABCDEF | |
// printf("SpiCharLCD v0.1a"); | |
// lcd_change_col(1); | |
// printf(">"); | |
// lcd_cmd(0xc0); | |
unsigned char i,d; | |
for(i=0;i<16;i++){ | |
d = eeprom_read(i); | |
lcd_data(d); | |
} | |
// lcd_data('S'); lcd_data('p'); lcd_data('i'); | |
// lcd_data('C'); lcd_data('h'); lcd_data('a'); lcd_data('r'); | |
// lcd_data('L'); lcd_data('C'); lcd_data('D'); lcd_data(' '); | |
// lcd_data('v'); lcd_data('0'); lcd_data('.'); lcd_data('1'); lcd_data('b'); | |
} | |
void initPWM(void){ | |
//PWM | |
//1)Set the PWM period by writing to the PR2 register. | |
//周期 = ( PR2 + 1 ) x 4 x 1クロック分の時間 x プリスケーラ値 | |
//10kHz 周期0.1ms = (PR2+1)x4x(1/8MHz)xPrescale | |
// 10^-4 = S*4*(1/8)*10^-6*P | |
// 2*10^2 = S*P | |
// 200 = (PR2+1)*P --- P=1 PR2=199 | |
CCP1CON = 0b00001100; //PWMを使用 | |
// T2CONbits.T2CKPS = 0b00; //プリスケーラ値1 | |
// PR2 = 199; | |
//2)Set the PWM duty cycle by writing to the | |
//CCPR1L register and CCP1CON<5:4> bits. | |
//PWM Duty Cycle = (CCPR1L:CCP1CON<5:4>) •TOSC • (TMR2 Prescale Value) | |
//50% 0.1ms*50% 0.05ms=50us | |
//PWM Duty Cycle = V * (1/8MHz) * 1 | |
//DC = V * 1/8 * 10^-6 | |
//50*10^-6 = V*1/8*10^-6 | |
//400 = V | |
//Vの下位2bitはCCP1x-CCP1Y | |
//vの上位8bitはCCPR1L | |
// CCPR1L = 100; | |
// CCP1CONbits.CCP1Y = 0; | |
// CCP1CONbits.CCP1X = 0; | |
//3)Make the CCP1 pin an output by clearing the TRISB<x> bit. | |
TRISBbits.TRISB3 = 0; | |
//4)Set the TMR2 prescale value and enable Timer2 by writing to T2CON. | |
// T2CONbits.TMR2ON = 1; | |
//50% | |
//プリスケーラ PR2 CCPR1L CCP1Y CCP1X | |
//10kHz 1 00 199 100 0 0 | |
//5kHz 4 01 99 50 0 0 | |
//1kHz 16 1x 124 62.5 1 0 | |
// changePWMindex(3); | |
changePWMeepromindex(40); | |
} | |
//void changePWMindex(unsigned char i){ | |
// T2CONbits.TMR2ON = 0; | |
// T2CONbits.T2CKPS = pwmary[i].ps; //プリスケーラ値1 | |
// PR2 = pwmary[i].pr; | |
// CCPR1L = pwmary[i].duty; | |
// | |
// CCP1CONbits.CCP1Y = pwmary[i].d1y; | |
// CCP1CONbits.CCP1X = pwmary[i].d1x; | |
// T2CONbits.TMR2ON = 1; | |
//} | |
void changePWMeepromindex(unsigned char i){ | |
T2CONbits.TMR2ON = 0; | |
T2CONbits.T2CKPS = eeprom_read(i); //プリスケーラ値1 | |
PR2 = eeprom_read(i+1); | |
CCPR1L = eeprom_read(i+2); | |
CCP1CONbits.CCP1Y = eeprom_read(i+3); | |
CCP1CONbits.CCP1X = eeprom_read(i+4); | |
T2CONbits.TMR2ON = 1; | |
} | |
//void changePWM(int ps,int pr,int duty,int d1y,int d1x){ | |
// T2CONbits.TMR2ON = 0; | |
// T2CONbits.T2CKPS = (unsigned int)ps; //プリスケーラ値1 | |
// PR2 = (unsigned int)pr; | |
// CCPR1L = (unsigned int)duty; | |
// CCP1CONbits.CCP1Y = (unsigned int)d1y; | |
// CCP1CONbits.CCP1X = (unsigned int)d1x; | |
// T2CONbits.TMR2ON = 1; | |
//} | |
void initAD(){ | |
ADCON1 = 0b1110; //4-1:D 0:A | |
//16TOSC 1 01 10MHz | |
ADCON1bits.ADCS2 = 1; | |
ADCON1bits.ADFM = 0; //左づめ | |
// ADCON0bits.ADCS = 0b01; | |
// ADCON0bits.CHS = 0b000; | |
// ADCON0bits.ADON = 1; | |
ADCON0 = 0b01000001; | |
} | |
unsigned char getAD(){ | |
ADCON0bits.GO = 1; | |
__delay_us(20); | |
while(ADCON0bits.GO){ | |
} | |
return ADRESH; | |
} | |
void initSPI(){ | |
SSPCONbits.SSPM = 0b0100; | |
SSPCONbits.SSPEN = 1; | |
TRISBbits.TRISB1 = 1; //SDI | |
TRISBbits.TRISB2 = 0; //SDO | |
TRISBbits.TRISB4 = 1; //SCK | |
TRISBbits.TRISB5 = 1; //SS | |
//mode SSPCON(CKP) SSPSTAT(CKE) | |
//1 0,1 0 0 | |
//3 1,1 1 0 | |
//0 0,0 0,1 | |
//2 1,0 1,1 | |
SSPCONbits.CKP = 1; | |
SSPSTATbits.CKE = 0; | |
PIE1bits.SSPIE = 1; | |
INTCONbits.PEIE = 1; | |
INTCONbits.GIE = 1; | |
} | |
void interrupt ISR(void) | |
{ | |
if(PIR1bits.SSPIF == 1){ | |
PIR1bits.SSPIF = 0; | |
ringbuf[wpoi] = SSPBUF; | |
wpoi = (wpoi+1) & RBUFMASK; | |
// TMR0 = GTIMER; | |
// INTCONbits.TMR0IE = 1; | |
}else if(INTCONbits.TMR0IF == 1){ | |
//rcvstate = 10; | |
swadcflg = 1; | |
TMR0 = GTIMER; | |
INTCONbits.TMR0IF = 0; | |
} | |
//lcd_data(SSPBUF); | |
} | |
void initTMR0(void){ | |
OPTION_REGbits.PS = 0b011; | |
OPTION_REGbits.PSA = 0; | |
OPTION_REGbits.T0CS = 0; | |
} |
0 件のコメント:
コメントを投稿