# 讀取電壓 ###### tags:`teach` `PIC16F18854` `TCA9548A` `MCB3421` <style> .red {color:red;} </style> ## 目的 用PIC16F18854經由TCA9548A再傳給MCP3421讀電壓再傳回來 ## IC介紹 ### DataSheet們 [PIC16F1885](https://ww1.microchip.com/downloads/en/DeviceDoc/PIC16(L)F18854-Data-Sheet-40001826E.pdf) [MCP3421](https://ww1.microchip.com/downloads/en/DeviceDoc/22003e.pdf) [TCA9548A](https://www.ti.com/lit/ds/symlink/tca9548a.pdf?ts=1612236040118&ref_url=https%253A%252F%252Fwww.google.com%252F) ### 有使用到的部份的整理 [I2C_PIC16F18854](https://hackmd.io/Au375pdfQ1KGA5u98tTthA) [MCP3421](https://hackmd.io/16GC_YXsSEOKopT5gyTq8g) [TCA9548A](https://hackmd.io/YSyg_tWhTlq319oRMVNAlg) ## 接線方式  其中的R2、R3是因為要讀取的電壓高於2.047v([為什麼會是這個數值後面會講解](https://hackmd.io/16GC_YXsSEOKopT5gyTq8g#OutPut-Code)),所以要先分壓再讀取 ## 程式說明 :::spoiler ### 大家都要有的初始化 ```c= void init(void){ PMD_Initialize(); PIN_MANAGER_Initialize(); OSCILLATOR_Initialize(); } void OSCILLATOR_Initialize(void){ // NOSC HFINTOSC; NDIV 1; OSCCON1 = 0x60; // CSWHOLD may proceed; SOSCPWR Low power; OSCCON3 = 0x00; // MFOEN disabled; LFOEN disabled; ADOEN disabled; SOSCEN disabled; EXTOEN disabled; HFOEN disabled; OSCEN = 0x00; // HFFRQ 4_MHz; OSCFRQ = 0x02; // HFTUN 0; OSCTUNE = 0x00; } void PMD_Initialize(void){ // CLKRMD CLKR enabled; SYSCMD SYSCLK enabled; SCANMD SCANNER enabled; FVRMD FVR enabled; IOCMD IOC enabled; CRCMD CRC enabled; NVMMD NVM enabled; PMD0 = 0x00; // TMR0MD TMR0 enabled; TMR1MD TMR1 enabled; TMR4MD TMR4 enabled; TMR5MD TMR5 enabled; TMR2MD TMR2 enabled; TMR3MD TMR3 enabled; NCOMD DDS(NCO) enabled; TMR6MD TMR6 enabled; PMD1 = 0x00; // ZCDMD ZCD enabled; DACMD DAC enabled; CMP1MD CMP1 enabled; ADCMD ADC enabled; CMP2MD CMP2 enabled; PMD2 = 0x00; // CCP2MD CCP2 enabled; CCP1MD CCP1 enabled; CCP4MD CCP4 enabled; CCP3MD CCP3 enabled; CCP5MD CCP5 enabled; PWM6MD PWM6 enabled; PWM7MD PWM7 enabled; PMD3 = 0x00; // CWG3MD CWG3 enabled; CWG2MD CWG2 enabled; CWG1MD CWG1 enabled; MSSP1MD MSSP1 enabled; UART1MD EUSART enabled; MSSP2MD MSSP2 enabled; PMD4 = 0x00; // DSMMD DSM enabled; CLC3MD CLC3 enabled; CLC4MD CLC4 enabled; SMT1MD SMT1 enabled; SMT2MD SMT2 enabled; CLC1MD CLC1 enabled; CLC2MD CLC2 enabled; PMD5 = 0x00; } void PIN_MANAGER_Initialize(void){ /** LATx registers */ LATA = 0x00; LATB = 0x00; LATC = 0x00; /** TRISx registers */ TRISA = 0x00; TRISB = 0xFF; TRISC = 0xFF; /** ANSELx registers */ ANSELC = 0xE7;//RC3 RC4設為數位 ANSELB = 0xFF; ANSELA = 0x00;//PORTA 設為數位 /** WPUx registers */ WPUE = 0x00; WPUB = 0x00; WPUA = 0x00; WPUC = 0x00; /** ODx registers */ ODCONA = 0x00; ODCONB = 0x00; ODCONC = 0x00; /** SLRCONx registers */ SLRCONA = 0xFF; SLRCONB = 0xFF; SLRCONC = 0xFF; /** INLVLx registers */ INLVLA = 0x00; INLVLB = 0xFF; INLVLC = 0xFF; INLVLE = 0x08; //智能SDA和SCL兩隻腳 SSP1CLKPPS = 0x13; //RC3->MSSP1:SCL1; RC3PPS = 0x14; //RC3->MSSP1:SCL1; RC4PPS = 0x15; //RC4->MSSP1:SDA1; SSP1DATPPS = 0x14; //RC4->MSSP1:SDA1; } ``` ### Master #### master暫存器設定 ```c= void master_init(void){ INTCONbits.GIE = 0;//中斷不智能 INTCONbits.PEIE = 0;//中斷不智能 PIR3bits.SSP1IF = 1;//等待傳輸 PIR3bits.BCL1IF = 1;//未檢測到衝突 PIE3bits.SSP1IE = 0;//不允許中斷 PIE3bits.BCL1IE = 0;//衝突不允許中斷 SSP1CON1=0x28; //智能SDA和SCL兩隻腳與設定為I2C master模式 SSP1CON2=0x00; SSP1CON3=0x00; SSP1STAT=0x00; SSP1BUF =0x00; SSP1STATbits.SMP=1; //1 =在標準速度模式(100 kHz和1 MHz)下禁用slew rate control SSP1STATbits.CKE=1; //1 =智能輸入邏輯,以使閾值符合SMBus規範 SSP1ADD=0x06; //100k Hz=0x06 數字越高頻率越慢 SSP1MSK=0xFF; //理論上這個在master應該是沒有用的,但還是讓她都為1乖一點 RA3=1; //可以用來看這個時候轉換成master了 } ``` #### 等等喔 ```c= void I2C_Master_Wait(){ while ((SSP1STAT & 0x04) || (SSP1CON2 & 0x1F));//確認有發起start後再動作 } ``` #### start ```c= void I2C_Master_Start(){ I2C_Master_Wait(); SSP1CON2bits.SEN = 1; //start } ``` #### restart ```c= void I2C_Master_RepeatedStart(){ I2C_Master_Wait(); SSP1CON2bits.RSEN = 1; //restart } ``` #### stop ```c= void I2C_Master_Stop(){ I2C_Master_Wait(); SSP1CON2bits.PEN = 1; //stop } ``` #### 寫入 ```c= void I2C_Master_Write(uint8_t data){ I2C_Master_Wait(); SSP1BUF = data; //將要傳送的data放進要經由I2C傳出的buffer裡 while(!PIR3bits.SSP1IF); // 等待bus上空閒 PIR3bits.SSP1IF = 0; //傳輸完成之後會為1,要用軟體回歸0,代表做完事了 } ``` #### 讀取 ```c= uint8_t I2C_Master_Read(uint8_t get){//get=0代表所有讀取資料完畢後會回傳nack(通常都是這個) //get=1代表所有讀取資料完畢後會回傳nack uint8_t temp; // 用來儲存讀取的資料的變數 I2C_Master_Wait(); SSP1CON2bits.RCEN = 1; //智能I2C的接收模式 I2C_Master_Wait(); temp = SSP1BUF; //將buffer收到的資料放進用來存取的變數裡 I2C_Master_Wait(); SSP1CON2bits.ACKDT = (get)?0:1;//get=1時,ack_data=NACK(0) //get=0時,ack_data=ACK(1) SSP1CON2bits.ACKEN = 1; //回傳ack_data給發送端 return temp; //引用I2C_Master_Read(uint8_t get)這行函式可得到讀取的資料 } ``` ::: ### main ```c= #define SLAVE_ADD 0x70 #define VOLTADE_ADD 0x68 uint8_t slave_feedback1, slave_feedback2; void main(void) { init(); I2C_Master_Start(); I2C_Master_Write((SLAVE_ADD << 1)|0); //傳tca9548a的id要寫 I2C_Master_Write(0x01); //寫入之後要用的是0通道 I2C_Master_Stop(); I2C_Master_Start(); I2C_Master_Write((SLAVE_ADD << 1)|0); I2C_Master_RepeatedStart(); //因為之後一定還會再接一個透過i2c的ic,所以必須restart,後面那顆 ic才會知道接下來的那個byte是他要判定的id I2C_Master_Write((VOLTADE_ADD << 1)|0); //傳後面那顆ic的id要寫 I2C_Master_Write(0x80);//寫給後面那顆ic的值 I2C_Master_Stop(); I2C_Master_Start(); I2C_Master_Write((SLAVE_ADD << 1)|0); I2C_Master_RepeatedStart(); I2C_Master_Write((VOLTADE_ADD << 1)|1); //跟後面那顆ic要資料 slave_feedback1=I2C_Master_Read(1); slave_feedback2=I2C_Master_Read(0);//傳NACK代表是最後一筆資料了 I2C_Master_Stop(); while(1){;} } ``` ## 邏輯分析儀驗證  \  再整理一下 寫個0662對應的電壓 :::danger ## 要注意的:star2: 加點東西 ::: :::warning ## 程式連結 [程式](https://github.com/linda8832825/i2c_18854_read_voltage.git) :::
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up