今回はパソコンとのシリアル通信に挑戦しましたがなかなか苦労しました。最初に結論だけ言うと、
逆に接続するよ!
ってことでした。それでは本文↓
使用するマイコンは PIC16F18326 で、秋月電子で販売しているこちらの超小型USBシリアル変換モジュールを使いました。
まずは PIC16F18326 のデータシートで EUSART の割り当てられているピンを確認してみると…
(※画像はデータシートを切り貼りしています)
このうち使用するのは受信の RX と送信の TX の2つですが、TX はデフォルトではどこにも割り当てられていないのね…割り付け必須ですな。
というわけで割り付け設定してレジスタの設定をして送受信の関数を作ってさあ実験だ!(ソースコードは最後に載せます)
PC は windows10 で Tera Term を使いました。
USBシリアル変換モジュールを PC に接続するとデバイスのインストールが始まり、それが完了するとこのように通信ポートが選択できるようになり、どうやら正常に認識されたようです。まずは一安心。
続いて1秒ごとに’w’を送信してみる。
キタ!(思いのほか上手くいってテンション高め)
この調子で受信したデータを LCD に表示させてみる。
・・・あれーおかしいぞー^^
ここから苦労の道が始まります。
まずは LCD に文字を表示させるテスト。問題なし。
受信は割り込みを使っていたため、main関数内で割り込みフラグをずっと監視してみる。やっぱりダメ。
しばらくうーんと考えてプログラムや配線を眺める。
ここでピンの割り付け設定が間違っていることに気付く。あれ、なんで設定間違ってるのに送信は出来たんだ?と思いつつ設定を直す。送信すら出来なくなった。
他のピンに割り付けてみる。やっぱりダメ。
ちなみにこの時点で2日が経過。
諦めかけていたそのとき、このサイトで気になる記述を発見。
※AE-FT234XのTXDはRaspberry PiのRXD、RXDはTXDと、逆になることに注意しましょう。私はこれにハマって数時間を無駄にしました。
…!。そういえばシリアル通信では送信と受信はクロスして接続するって聞いたことがあったような…
・
・
・
あああああ!というわけで早速 RX と TX を逆にしてみる。送信できた!受信できた!以上!
どうやら最初に送信だけできたのはピンの割り付けと配線の両方間違っていて、たまたま送信だけ噛み合ってしまったということみたいです。送信できて舞い上がっていたのがアホらしいです。
それでは最後に受信したデータを LCD に表示するソースコードでも載せておきますね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
#pragma config FEXTOSC = OFF // FEXTOSC External Oscillator mode Selection bits (Oscillator not enabled) #pragma config RSTOSC = HFINT1 // Power-up default value for COSC bits (HFINTOSC (1MHz)) #pragma config CLKOUTEN = OFF // Clock Out Enable bit (CLKOUT function is disabled; I/O or oscillator function on OSC2) #pragma config CSWEN = ON // Clock Switch Enable bit (Writing to NOSC and NDIV is allowed) #pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled) #pragma config MCLRE = ON // Master Clear Enable bit (MCLR/VPP pin function is MCLR; Weak pull-up enabled) #pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled) #pragma config WDTE = OFF // Watchdog Timer Enable bits (WDT disabled; SWDTEN is ignored) #pragma config LPBOREN = OFF // Low-power BOR enable bit (ULPBOR disabled) #pragma config BOREN = OFF // Brown-out Reset Enable bits (Brown-out Reset disabled) #pragma config BORV = LOW // Brown-out Reset Voltage selection bit (Brown-out voltage (Vbor) set to 2.45V) #pragma config PPS1WAY = ON // PPSLOCK bit One-Way Set Enable bit (The PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle) #pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will cause a Reset) #pragma config DEBUG = OFF // Debugger enable bit (Background debugger disabled) #pragma config WRT = OFF // User NVM self-write protection bits (Write protection off) #pragma config LVP = OFF // Low Voltage Programming Enable bit (High Voltage on MCLR/VPP must be used for programming.) #pragma config CP = OFF // User NVM Program Memory Code Protection bit (User NVM code protection disabled) #pragma config CPD = OFF // Data NVM Memory Code Protection bit (Data NVM code protection disabled) #include <xc.h> #include <stdio.h> #include "i2c.h" #include "lcd_i2c.h" #define _XTAL_FREQ 4000000 void init(){ OSCFRQ = 0x03; //4MHz OSCCON1bits.NDIV = 0x0; //Clock Divider 1/1 TRISA = 0b00111001; TRISC = 0b00000000; ANSELA = 0b00000000; ANSELC = 0b00000000; WPUA = 0b00000000; WPUC = 0b00000000; PORTA = 0b00000000; PORTC = 0b00000000; } void EUSART_Init(){ TX1STA = 0x20; RC1STA = 0x90; BAUD1CON = 0x08; SP1BRG = 25; PIE1bits.RCIE = 1; PIR1bits.RCIF = 0; RXPPS = 0x00; RA1PPS = 0x14; } void EUSART_Send(char c){ while(TRMT == 0); TX1REG = c; } char EUSART_Receive(){ if(PIR1bits.RCIF == 1){ if((RC1STAbits.OERR)||(RC1STAbits.FERR)){ RC1STA = 0; RC1STA = 0x90; return 0xff; } else return RC1REG; } else return 0; } void interrupt isr(){ if(PIR1bits.RCIF == 1){ lcd_DATA(EUSART_Receive()); } } int main() { init(); GIE = 1; PEIE = 1; I2C_Master_Init(100000); lcd_Init(); EUSART_Init(); while(1){ } } |
▼I2Cライブラリ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#include<xc.h> #define _XTAL_FREQ 4000000 void I2C_Master_Init(const unsigned long c){ SSP2CON1 = 0x28; //SSP2 Module as Master SSP2CON2 = 0x00; SSP2CON3 = 0x00; SSP2ADD = (_XTAL_FREQ/(4*c))-1; //Setting Clock Speed SSP2STAT = 0x80; SSP2CLKPPS = 0x14; //PPS Settings SSP2DATPPS = 0x15; RC4PPS = 0x1a; RC5PPS = 0x1b; } void I2C_Master_Wait(){ while ((SSP2STAT & 0x04) || (SSP2CON2 & 0x1F)); //Transmit is in progress } void I2C_Master_Start(){ I2C_Master_Wait(); SSP2CON2bits.SEN = 1; //Initiate start condition } void I2C_Master_RepeatedStart(){ I2C_Master_Wait(); SSP2CON2bits.RSEN = 1; //Initiate repeated start condition } void I2C_Master_Stop(){ I2C_Master_Wait(); SSP2CON2bits.PEN = 1; //Initiate stop condition } void I2C_Master_Write(unsigned d){ I2C_Master_Wait(); SSP2BUF = d; //Write data to SSP2BUF } unsigned short I2C_Master_Read(unsigned short a){ unsigned short temp; I2C_Master_Wait(); SSP2CON2bits.RCEN = 1; I2C_Master_Wait(); temp = SSP2BUF; //Read data from SSP2BUF I2C_Master_Wait(); SSP2CON2bits.ACKDT = a; //Acknowledge bit SSP2CON2bits.ACKEN = 1; //Acknowledge sequence return temp; } |
1 2 3 4 5 6 7 |
void I2C_Master_Init(const unsigned long c); void I2C_Master_Wait(); void I2C_Master_Start(); void I2C_Master_RepeatedStart(); void I2C_Master_Stop(); void I2C_Master_Write(unsigned d); unsigned short I2C_Master_Read(unsigned short a); |
▼LCDライブラリ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
#include "i2c.h" #include <xc.h> #define _XTAL_FREQ 4000000 //#define CONTRAST 0x18 //for 3.3V #define CONTRAST 0x08 //for 5V const char lcd_DDRAM[4] = {0x00, 0x40, 0x14, 0x54}; void lcd_INST(char command){ I2C_Master_Start(); I2C_Master_Write(0x7C); //SlaveAdress + Write I2C_Master_Write(0x00); //Instruction I2C_Master_Write(command); //data byte I2C_Master_Stop(); __delay_us(30); } void lcd_DATA(char data){ I2C_Master_Start(); I2C_Master_Write(0x7C); //SlaveAdress + Write I2C_Master_Write(0x40); //Data I2C_Master_Write(data); //data byte I2C_Master_Stop(); __delay_us(30); } void lcd_Init(){ __delay_ms(40); lcd_INST(0x38); //Function Set lcd_INST(0x39); //Function Set lcd_INST(0x14); //Internal OSC Frequency lcd_INST(0x70 + (CONTRAST & 0x0f)); //Contrast Set lcd_INST(0x54 + ((CONTRAST & 0xf0)>>4)); //Power/ICON/Contrast control lcd_INST(0x6c); //Follower control __delay_ms(200); lcd_INST(0x38); //Function Set lcd_INST(0x0c); //Display ON/OFF control lcd_INST(0x01); //Clear Display __delay_ms(2); } void lcd_SetCursor(char x,char y){ char d = lcd_DDRAM[y] + x; lcd_INST(0x80+d); } |
1 2 3 4 |
void lcd_INST(char command); void lcd_DATA(char data); void lcd_Init(); void lcd_SetCursor(char x,char y); |
LCD についてはこちらの記事を参照してください。
それではまた次回。