Thứ Tư, 28 tháng 11, 2018

Bài 6. PIC 18F450 Chế Độ SPI

Giới thiệu

Giao tiếp ngoại vi nối tiếp (SPI) là một giao thức dữ liệu nối tiếp đồng bộ thường được sử dụng để liên lạc nhanh qua khoảng cách ngắn.
SPI là một giao thức đồng bộ cho phép thiết bị chủ (thường là vi điều khiển) bắt đầu truyền thông với một thiết bị nô lệ. Nó là một giao thức truyền thông song công hoàn chỉnh.
SPI sử dụng các đường đồng hồ và dữ liệu riêng biệt với dòng chọn để chọn thiết bị mà chúng tôi muốn liên lạc.
SPI thường được sử dụng để giao tiếp nhanh chóng với các thiết bị như thẻ SD, chip EEPROM, một số bộ ADC TI vv
Nó có thể giao tiếp với nhiều nô lệ.
Có bốn chốt cơ bản được sử dụng trong giao tiếp SPI PIC18F4550, đó là:
1. SCK (Đồng hồ nối tiếp)
2. SDI (Dữ liệu nối tiếp trong)
3. SDO (Dữ liệu nối tiếp)
4. SS (Chọn Slave)
Sơ đồ kết nối chung của các thiết bị chủ và phụ trợ PIC18F4550:
                           
PIC18F4550 SPI Pins
PIC18F4550 SPI Pins


       1. SCK: (Đồng hồ nối tiếp)
           Tín hiệu đồng hồ (SCK) được cung cấp bởi tổng thể để cung cấp đồng bộ hóa.
           Chỉ thiết bị chính mới có thể điều khiển đường đồng hồ, SCK.
        2.  SDI: (Dữ liệu nối tiếp trong)
            SDI là đầu vào dữ liệu nối tiếp mang dữ liệu vào thiết bị.
        3.  SDO: (Dữ liệu nối tiếp ra)
           Đây là tín hiệu đầu ra dữ liệu nối tiếp. Nó mang dữ liệu ra khỏi thiết bị.
        4. SS: (Chọn Slave)
            Nó là một tín hiệu chọn nô lệ. Trong chế độ chủ, chúng ta có thể sử dụng nó để chọn thiết bị (slave) mà chúng ta muốn giao tiếp.
            Đây là tín hiệu hoạt động thấp, vì vậy mức thấp trên dòng này sẽ cho biết SPI đang hoạt động.
            Khi nhiều nô lệ được sử dụng thì các chốt GPIO của vi điều khiển được sử dụng để chọn các thiết bị nô lệ.

Làm việc của PIC18F4550 SPI

SPI cho phép 8 bit dữ liệu được truyền đồng bộ và nhận đồng thời.
Dữ liệu rời khỏi bản gốc được đặt trên đường dây SDO (đầu ra dữ liệu nối tiếp) và dữ liệu nhập vào tổng thể đi qua đường dây SDI (đầu vào dữ liệu nối tiếp).
Đồng hồ (SCK), được tạo bởi thiết bị chính. Nó kiểm soát thời gian và tốc độ trao đổi dữ liệu giữa hai thiết bị .
Master chọn thiết bị sử dụng SS (slave select) line.
        
PIC18F4550 SPI Làm việc
PIC18F4550 SPI Làm việc

SSPSR: Đây là thanh ghi thay đổi được sử dụng để chuyển dữ liệu vào hoặc ra. Nó không phải là người dùng có thể truy cập.
SSPBUF: Đây là thanh ghi bộ đệm mà các byte dữ liệu được ghi vào hoặc đọc từ đó.
  • Khi vi điều khiển PIC18F4550 muốn truyền dữ liệu, nó sẽ sao chép dữ liệu trong thanh ghi SSPBUF (SSP Buffer) bằng vi điều khiển.
  • Sau đó, dữ liệu đó được chuyển đến thanh ghi thay đổi SPS SSPSR tức là sẽ thay đổi dữ liệu đó từng chút một trên mỗi sự kiện đồng hồ từ master đến slave thông qua SDO. Nó truyền hoặc thay đổi bit MSB đầu tiên.
  • Trong khi ở phía bên nô lệ dữ liệu được chuyển qua bit bit SDI bằng bit sử dụng cùng một thanh ghi SSPSR và chuyển đến SSPBUF khi một byte dữ liệu đã được trao đổi giữa hai thiết bị.
  • Sau đó, cần phải đọc dữ liệu từ SSPBUF tại bản gốc trước khi viết. Nếu không, dữ liệu đến sẽ bị mất. Điều này sẽ cho biết tràn bộ đệm.
  • Thiết bị chính truyền tín hiệu chọn đồng hồ và nô lệ. Thiết bị nô lệ chờ các tín hiệu này và sử dụng chúng khi xử lý dữ liệu SPI.
Lưu ý: Khi chính truyền dữ liệu đến thiết bị phụ, slave cũng truyền byte yêu cầu hoặc byte đồng thời. Vì vậy, sau khi truyền dữ liệu qua SSPBUF từ master đến slave, dữ liệu nên được đọc ngay lập tức để tránh tràn. Nó cũng được áp dụng cho truyền từ thiết bị phụ để làm chủ.

Đăng ký SPI

Để cấu hình PIC18F4550 cho giao thức truyền thông SPI sau hai thanh ghi được sử dụng
SSPSTAT: Trạng thái SSP Đăng ký chế độ SPI
Đăng ký trạng thái SSP cho chế độ SPIĐăng ký SSPSTAT

Bit 0 - BF: Bit trạng thái đệm đầy đủ
       1 = Nhận hoàn tất, SSPBUF đã đầy.
       0 = Nhận không hoàn thành, SSPBUF trống.
Bit 6 - CKE: SPI Clock Chọn bit
Khi CKP = 0
       0 = Dữ liệu được truyền trên cạnh rơi của SCK
       1 = Dữ liệu được truyền trên cạnh tăng của SCK
Khi CKP = 1
       0 = Dữ liệu được truyền trên cạnh tăng của SCK
       1 = Dữ liệu được truyền trên cạnh rơi của SCK
Bit 7 - SMP: bit mẫu
 Chế độ SPI chính:
       1 = Dữ liệu đầu vào được lấy mẫu ở cuối thời gian đầu ra dữ liệu
       0 = Dữ liệu đầu vào được lấy mẫu ở giữa thời gian đầu ra dữ liệu
Chế độ SPI Slave:
       SMP phải được xóa khi SPI được sử dụng trong chế độ Slave.
Lưu ý: Các bit khác trong thanh ghi này được sử dụng cho giao thức I2C.

SSPCON1: Đăng ký kiểm soát SSP cho chế độ SPI
Kiểm soát SSP Đăng ký chế độ SPI
Đăng ký SSPCON1 

Bit 3: 0 - SSPM3: SSPM0: Chế độ cổng nối tiếp đồng bộ chính Chọn bit
Các bit này được sử dụng để chọn chế độ Master hoặc Slave và cũng có thể chọn đồng hồ.
SSPM3: SSPM0
Chế độ
Trạng thái pin đồng hồ / SS
0000
Chế độ SPI chính
Fosc / 4
0001
Chế độ SPI chính
Fosc / 16
0010
Chế độ SPI chính
Fosc / 64
0011
Chế độ SPI chính
Đầu ra TMR2 / 2
0100
Chế độ Slave SPI
Đã bật SS
0101
Chế độ Slave SPI
SS bị tắt, được sử dụng làm pin I / O
Các kết hợp khác được sử dụng cho Giao thức I2C.
Bit 4 - CKP: Đồng hồ phân cực Chọn bit
       1 = Trạng thái nhàn rỗi cho đồng hồ là mức cao
       0 = Trạng thái nhàn rỗi cho đồng hồ là mức thấp
Bit 5 - SSPEN: Cổng nối tiếp đồng bộ chính cho phép bit
       1 = Bật cổng nối tiếp và cấu hình SCK, SDO, SDI và SS làm chân cổng nối tiếp.
       0 = Tắt cổng nối tiếp và cấu hình các chân này làm chân cổng I / O.
Bit 6 - SSPOV: Nhận bit chỉ báo tràn
Chế độ SPI Slave:
       1 = Một byte mới được nhận trong khi thanh ghi SSPBUF vẫn giữ dữ liệu trước đó. Trong trường hợp tràn, dữ liệu trong SSPSR bị mất. 
       0 = Không tràn
Bit 7 - WCOL: Ghi va chạm Phát hiện bit (Chỉ chế độ phát)
        1 = Thanh ghi SSPBUF được viết trong khi nó vẫn đang truyền từ trước
     (phải được xóa thông qua phần mềm)
        0 = Không có va chạm

Tầm quan trọng của các bit CKP và CKE
CKP  quyết định tính phân cực của đồng hồ, có nghĩa là trạng thái không hoạt động của đồng hồ. Các thiết bị SPI cần được lập trình với cùng cực. Sau đó cả hai thiết bị sẽ gửi hoặc nhận dữ liệu cùng một lúc. Nhưng dữ liệu này có ý nghĩa hoặc giả phụ thuộc vào ứng dụng.
Điều này dẫn đến ba cơ hội sau,
  1. Thạc sĩ gửi dữ liệu, nô lệ gửi dữ liệu giả
  2. Thạc sĩ gửi dữ liệu giả, nô lệ gửi dữ liệu
  3. Master gửi dữ liệu, slave gửi dữ liệu.
CKE quyết định nên truyền dữ liệu cạnh / tăng nào. Nhưng dữ liệu thực tế được đặt hoặc chốt trên đường SDO đối diện với cạnh truyền dữ liệu.
CKE và CKP cùng nhau quyết định chế độ SPI nào được sử dụng cho tất cả các lần chuyển SPI.
Chế độ SPI
CKP
CKE
0,0
0
1
0,1
0
0
1,0
1
1
1,1
1
0
Biểu đồ thời gian sau hiển thị thông tin SPI thực tế
             
Sơ đồ thời gian SPI

Lập trình PIC18F4550 SPI

Khởi tạo:
Cấu hình các chân PORT được sử dụng cho truyền thông SPI.
Đồng thời tắt mã SS tức là SS = 1.
Xóa SSPIF.
Cấu hình đăng ký SSPSTAT bằng cách thiết lập bit SMP, CKE để thay đổi dữ liệu ở cạnh tăng / giảm của đồng hồ và làm cho bộ đệm đầy (BF) = 0.
Khởi tạo SSPCON đăng ký bằng cách thiết lập bit SPEN = 1 cho SSP Enable. CKP cho biết cực đồng hồ.
Chọn chế độ của chế độ SPI master / slave và quyết định tốc độ khi bạn yêu cầu sử dụng SSPM3: SSPM0 trong thanh ghi SSPCON1.
Ngoài ra de-multiplex tất cả bốn chân SS, SDO, SDI và SCK bằng cách sử dụng đăng ký khác nhau tức là ADCON0, ADCON1.
SPI_Master
void SPI_Init_Master()
{
    /* PORT definition for SPI pins*/    
    TRISBbits.TRISB0 =1; /* RB0 as input(SDI) */
    TRISBbits.TRISB1=0;  /* RB1 as output(SCK) */
    TRISAbits.TRISA5=0;  /* RA5 as a output(SS') */
    TRISCbits.TRISC7=0;  /* RC7 as output(SDO) */

    /* To initialize SPI Communication configure following Register*/
    CS = 1;
    SSPSTAT=0x40;  /* Data change on rising edge of clk , BF=0*/
    SSPCON1=0x22;  /* Master mode,Serial enable,
    idle state low for clk, fosc/64 */ 
    PIR1bits.SSPIF=0;

    /* Disable the ADC channel which are on for multiplexed pin when
    used as an input */    
    ADCON0=0;   /* This is for de-multiplexed the 
    SCL and SDI from analog pins*/
    ADCON1=0x0F;  /* This makes all pins as digital I/O */
}

SPI_Slave
void SPI_Init_Slave()
{
    /* PORT definition for SPI pins*/    
    TRISBbits.TRISB0 = 1; /* RB0 as input(SDI) */
    TRISBbits.TRISB1 = 1; /* RB1 as output(SCK) */
    TRISAbits.TRISA5 = 1; /* RA5 as a output(SS') */
    TRISCbits.TRISC7 = 0; /* RC7 as output(SDO) */

    /* To initialize SPI Communication configure following Register*/
    CS = 1;
    SSPSTAT=0x40;  /* Data change on rising edge of clk , BF=0*/
    SSPCON1=0x24;  /* Slave mode,Serial enable, idle state 
    high for clk */ 
    PIR1bits.SSPIF=0;

    /* Disable the ADC channel which are on for multiplexed pin 
    when used as an input */    
    ADCON0=0;   /* This is for de-multiplexed the SCL
    and SDI from analog pins*/
    ADCON1=0x0F;  /* This makes all pins as digital I/O */    
}

Chế độ truyền
  1. Sao chép dữ liệu vào thanh ghi SSPBUF.
  2. Đợi cờ ngắt SSPIF để cài đặt được đặt sau khi truyền hoàn toàn 1 byte.
  3. Xóa SSPIF
  4. Đọc đăng ký SSPBUF ngay lập tức để xóa dữ liệu.
  5. Trước khi truyền / viết không. của byte làm cho SS hoạt động tức là SS = 0 và sau khi hoàn thành truyền / ghi vô hiệu hóa nó, SS = 1.
void SPI_Write(unsigned char x)
{
    unsigned char data_flush;
    SSPBUF=x;   /* Copy data in SSBUF to transmit */
    while(!PIR1bits.SSPIF); /* Wait for complete 1 byte transmission */
    PIR1bits.SSPIF=0;  /* Clear SSPIF flag */
    data_flush=SSPBUF;  /* Flush the data */
}

Chế độ nhận
  1. Truyền byte tuôn ra bằng cách sao chép dữ liệu vào thanh ghi SSPBUF (tùy chọn).
  2. Đợi cờ ngắt SSPIF để đặt được đặt sau khi nhận được 1 byte hoàn chỉnh.
  3. Đọc dữ liệu từ SSPBUF đăng ký và trả về SSPBUF.
unsigned char SPI_Read()
{    
    SSPBUF=0xff;  /* Copy flush byte in SSBUF */
    while(!PIR1bits.SSPIF); /* Wait for complete 1 byte transmission */
    PIR1bits.SSPIF=0;
    return(SSPBUF);  /* Return received byte */   
}

ví dụ 1

Hãy thiết lập giao tiếp SPI giữa vi điều khiển PIC18F4550. Một PIC sẽ hoạt động như thiết bị chính và thiết bị phụ khác.
Bằng cách sử dụng giao tiếp SPI này, một vi điều khiển PIC sẽ bắt đầu đếm liên tục từ 0-15 và truyền các giá trị này đến một vi điều khiển PIC khác. Một vi điều khiển PIC khác sẽ phát sáng LED được kết nối trên các chương trình PORT đếm.

Sơ đồ

Master-Slave thông tin liên lạc giữa hai PIC micrcontrollerMaster-Slave thông tin liên lạc giữa hai PIC18F4550  micrcontroller

Chương trình

SPI MASTER
#include <pic18f4550.h>
#include "Configuration_Header_File.h"

#define CS LATA5

void SPI_Write(unsigned char);
void SPI_Init_Master();
unsigned char SPI_Read();
void MSdelay(unsigned int);

void main() 
{
    int i;
    OSCCON = 0x72;  /* Use internal frequency 8 MHz */    
    INTCON2bits.RBPU=0;  /* Enable internal Pull-up of PORTB */
    SPI_Init_Master();  /* Initialize SPI communication */
    MSdelay(10);
    
    while(1)
    {
        CS = 0;
        for(i=0;i<=15;i++) /* Start counter */
        {
            SPI_Write(i); /* Send counter value to Slave */
            MSdelay(1000);
        }
        CS = 1;
        i=0;
    
    }
}

void SPI_Init_Master()
{
    /* PORT definition for SPI pins*/    
    TRISBbits.TRISB0 = 1; /* RB0 as input(SDI) */
    TRISBbits.TRISB1 = 0; /* RB1 as output(SCK) */
    TRISAbits.TRISA5 = 0; /* RA5 as a output(SS') */
    TRISCbits.TRISC7 = 0; /* RC7 as output(SDO) */

    /* To initialize SPI Communication configure following Register*/
    CS = 1;
    SSPSTAT=0x40;  /* Data change on rising edge of clk,BF=0*/
    SSPCON1=0x22;  /* Master mode,Serial enable,
    idle state low for clk, fosc/64 */ 
    PIR1bits.SSPIF=0;

    /* Disable the ADC channel which are on for multiplexed pin
    when used as an input */    
    ADCON0=0;   /* This is for de-multiplexed the SCL
    and SDI from analog pins*/
    ADCON1=0x0F;  /* This makes all pins as digital I/O */    
}

void SPI_Write(unsigned char x)
{
    unsigned char data_flush;
    SSPBUF=x;   /* Copy data in SSBUF to transmit */

    while(!PIR1bits.SSPIF); /* Wait for complete 1 byte transmission */
    PIR1bits.SSPIF=0;  /* Clear SSPIF flag */
    data_flush=SSPBUF;  /* Flush the data */
}

unsigned char SPI_Read()
{    
    SSPBUF=0xff;  /* Copy flush data in SSBUF */
    while(!PIR1bits.SSPIF); /* Wait for complete 1 byte transmission */
    PIR1bits.SSPIF=0;
    return(SSPBUF);  /* Return received data.*/   
}

/*************************Delay Function****************************/
void MSdelay(unsigned int val) /* Delay of 1 ms for 8MHz Freq. */
{
     unsigned int i,j;
        for(i=0;i<val;i++)
            for(j=0;j<165;j++);
}

SPI SLAVE
#include <pic18f4550.h>
#include "Configuration_Header_File.h"

#define CS LATA5
#define LED LATD

void SPI_Write(unsigned char);
void SPI_Init_Slave();
unsigned char SPI_Read();
void MSdelay(unsigned int);


void main() 
{
    int i;
    
    TRISD =0;   /* PORT initialize as output */
    OSCCON = 0x72;  /* Use internal osc. frequency 8 MHz */    
    INTCON2bits.RBPU=0;  /* Enable internal Pull-up of PORTB */
    SPI_Init_Slave();  /* Initialize SPI communication as a slave */             
    
    while(1)
    {
     LED = SPI_Read();       
    }
}

void SPI_Init_Slave()
{
    /* PORT definition for SPI pins*/    
    TRISBbits.TRISB0 = 1; /* RB0 as input(SDI) */
    TRISBbits.TRISB1 = 1; /* RB1 as output(SCK) */
    TRISAbits.TRISA5 = 1; /* RA5 as a output(SS') */
    TRISCbits.TRISC7 = 0; /* RC7 as output(SDO) */

    /* To initialize SPI Communication configure following Register*/
    CS = 1;
    SSPSTAT=0x40;  /* Data change on rising edge of clk , BF=0*/
    SSPCON1=0x24;  /* Slave mode,Serial enable, idle state
    high for clk */ 
    PIR1bits.SSPIF=0;
    /* Disable the ADC channel which are on for multiplexed pin
    when used as an input */    
    ADCON0=0;   /* This is for de-multiplexed the SCL
    and SDI from analog pins*/
    ADCON1=0x0F;  /* This makes all pins as digital I/O */    
}

void SPI_Write(unsigned char x)
{
    unsigned char data_flush;
    SSPBUF=x;   /* Copy data in SSBUF to transmit */

    while(!PIR1bits.SSPIF); /* Wait for complete 1 byte transmission */
    PIR1bits.SSPIF=0;  /* Clear SSPIF flag */
    data_flush=SSPBUF;  /* Flush received data */
}

unsigned char SPI_Read()
{    
    SSPBUF=0xff;  /* Copy flush data in SSBUF */
    while(!PIR1bits.SSPIF); /* Wait for complete 1 byte transmission */
    PIR1bits.SSPIF=0;  /* Clear SSPIF flag */
    return(SSPBUF);  /* Return received data.*/   
}


/***************************Delay Function************************/
void MSdelay(unsigned int val) /* Delay of 1 ms for 8MHz Frequency */
{
     unsigned int i,j;
        for(i=0;i<val;i++)
            for(j=0;j<165;j++);
}


Không có nhận xét nào:

Đăng nhận xét