2011年6月19日 星期日

DIY - PIC:PIC18F4550 SPI 函數庫程式 (八十五)

DIY - PICPIC18F4550 SPI 函數庫程式 (十五)

Microchip C18 有內置支持 PIC18F4550 SPI串列外設介面函數庫模塊 (spi.h),衹需要用包括 spi 頭文件 ()。然後再呼叫不同的功能,便可控制 SPI串列外設介面。


功能 CloseSPI (禁止SSP 模組) 
原型void CloseSPI ( void ); 
說明該函數禁止SSP 模組。相關引腳恢復為普通I/O 口功能。由TRISC LATC 負責實現I/O 控制。 
檔案名closespi.c 
範例CloseSPI(); 

功能 DataRdySPI (確定SSPBUF 中是否有資料) 
原型unsigned char DataRdySPI ( void ); 
說明:該函數確定 SSPBUF 寄存器中是否有資料位元組可讀。 
返回值:如果 SSPBUF 寄存器中沒有資料,為0 ;如果 SSPBUF 寄存器中有資料,則為1 
檔案名:dtrdyspi.c 
範例:while (!DataRdySPI()); 

功能 getsSPI (SPI 匯流排讀取一個資料串) 
原型void getsSPI ( unsigned char *rdptr,unsigned char length ); 
參數rdptr - 指向存放從SPI 器件中讀取資料的位址的指標。 
            length - 要從SPI 器件中讀取資料的位元組數。 
說明:該函數從SPI 匯流排讀取一個預定義長度的資料串。 
檔案名:getsspi.c 
範例:unsigned char wrptr(10); getsSPI(wrptr, 10); 

功能 OpenSPI  (初始化 SSP 模組) 
原型void OpenSPI ( unsigned char sync_mode, unsigned char bus_mode, unsigned char smp_phase); 
參數:  sync_mode - 取下列值之一,在spi.h 中定義:
SPI_FOSC_4
SPI 主模式, clock = FOSC/4
SPI_FOSC_16
SPI 主模式, clock = FOSC/16
SPI_FOSC_64
SPI 主模式, clock = FOSC/64
SPI_FOSC_TMR2
SPI 主模式, clock = TMR2 輸出/2
SLV_SSON SPI
從模式,使能/SS 引腳控制
SLV_SSOFF SPI
從模式, 禁止/SS 引腳控制

              bus_mode - 取下列值之一,在spi.h 中定義:
MODE_00
設置SPI 匯流排為模式 0,0
MODE_01
設置SPI 匯流排為模式 0,1
MODE_10
設置SPI 匯流排為模式 1,0
MODE_11
設置SPI 匯流排為模式 1,1

              smp_phase - 取下列值之一,在spi.h 中定義:
SMPEND
在輸出資料的末端進行輸入資料採樣
SMPMID
在輸出資料的中間進行輸入資料採樣

說明:該函數設置供SPI 匯流排器件使用的SSP 模組。 
檔案名openspi.c 
範例OpenSPI(SPI_FOSC_16, MODE_00, SMPEND); 

功能 putsSPI (SPI 匯流排寫一個資料串) 
原型void putsSPI( unsigned char *wrptr ); 
參數wrptr -指向要寫到SPI 匯流排的值的指標。 
說明:該函數向SPI 匯流排器件寫一個資料串。當在資料串中讀到一個空字元時函數終止(空字元不會寫到匯流排)。 
檔案名putsspi.c 
範例unsigned char wrptr[] = “Hello!”; putsSPI(wrptr); 

功能 getcSPI / ReadSPI  (SPI 匯流排上讀取一個位元組) 
原型unsigned char ReadSPI( void ); 
說明:該函數啟動一個SPI 匯流排週期,來採集一位元組資料。 
返回值: 該函數返回在SPI 讀週期內讀取的一位元組資料。 
檔案名readspi.c 
範例char x; x = ReadSPI(); 

功能 putcSPI / WriteSPI   (SPI 匯流排寫一個位元組) 
原型unsigned char WriteSPI(unsigned char data_out ); 
參數:data_out - 要寫到SPI 匯流排的值。 
說明:該函數寫一個位元組的資料,然後檢查是否有寫衝突。 
返回值:如果沒有發生寫衝突,為 0 ;如果發生寫衝突,則為 -1
檔案名:writespi.c 
範例:WriteSPI(‘a’); 

下面的例子說明了如何使用SSP 模組與Microchip 25C080 SPI 電可擦除記憶體進行通訊。
#include
#include
// FUNCTION Prototypes
void main(void);
void set_wren(void);
void busy_polling(void);
unsigned char status_read(void);
void status_write(unsigned char data);
void byte_write(unsigned char addhigh,
unsigned char addlow,
unsigned char data);
void page_write(unsigned char addhigh,
unsigned char addlow,
unsigned char *wrptr);
void array_read(unsigned char addhigh,
unsigned char addlow,
unsigned char *rdptr,
unsigned char count);
unsigned char byte_read(unsigned char addhigh,
unsigned char addlow);
// VARIABLE Definitions
unsigned char arraywr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,0};
//25C040/080/160 page write size
unsigned char arrayrd[16];
unsigned char var;
#define SPI_CS LATCbits.LATC2
//**************************************************
void main(void)
{
TRISCbits.TRISC2 = 0;
SPI_CS = 1; // ensure SPI memory device
// Chip Select is reset
OpenSPI(SPI_FOSC_16, MODE_00, SMPEND);
set_wren();
status_write(0);
busy_polling();
set_wren();
byte_write(0x00, 0x61, 'E');
busy_polling();
var = byte_read(0x00, 0x61);
set_wren();
page_write(0x00, 0x30, arraywr);
busy_polling();
array_read(0x00, 0x30, arrayrd, 16);
var = status_read();
CloseSPI();
while(1);
}
void set_wren(void)
{
SPI_CS = 0; //assert chip select
var = putcSPI(SPI_WREN); //send write enable command
SPI_CS = 1; //negate chip select
}
void page_write (unsigned char addhigh,
unsigned char addlow,
unsigned char *wrptr)
{
SPI_CS = 0; //assert chip select
var = putcSPI(SPI_WRITE); //send write command
var = putcSPI(addhigh); //send high byte of address
var = putcSPI(addlow); //send low byte of address
putsSPI(wrptr); //send data byte
SPI_CS = 1; //negate chip select
}
void array_read (unsigned char addhigh,
unsigned char addlow,
unsigned char *rdptr,
unsigned char count)
{
SPI_CS = 0; //assert chip select
var = putcSPI(SPI_READ); //send read command
var = putcSPI(addhigh); //send high byte of address
var = putcSPI(addlow); //send low byte of address
getsSPI(rdptr, count); //read multiple bytes
SPI_CS = 1;
}
void byte_write (unsigned char addhigh,
unsigned char addlow,
unsigned char data)
{
SPI_CS = 0; //assert chip select
var = putcSPI(SPI_WRITE); //send write command
var = putcSPI(addhigh); //send high byte of address
var = putcSPI(addlow); //send low byte of address
var = putcSPI(data); //send data byte
SPI_CS = 1; //negate chip select
}
unsigned char byte_read (unsigned char addhigh,
unsigned char addlow)
{
SPI_CS = 0; //assert chip select
var = putcSPI(SPI_READ); //send read command
var = putcSPI(addhigh); //send high byte of address
var = putcSPI(addlow); //send low byte of address
var = getcSPI(); //read single byte
SPI_CS = 1;
return (var);
}
unsigned char status_read (void)
{
SPI_CS = 0; //assert chip select
var = putcSPI(SPI_RDSR); //send read status command
var = getcSPI(); //read data byte
SPI_CS = 1; //negate chip select
return (var);
}
void status_write (unsigned char data)
{
SPI_CS = 0;
var = putcSPI(SPI_WRSR); //write status command
var = putcSPI(data); //status byte to write
SPI_CS = 1; //negate chip select
}
void busy_polling (void)
{
do
{
SPI_CS = 0; //assert chip select
var = putcSPI(SPI_RDSR); //send read status command
var = getcSPI(); //read data byte
SPI_CS = 1; //negate chip select
} while (var & 0x01); //stay in loop until !busy
}
 
2011 06 19 天氣報告 
氣溫:29.3 @ 22:00 
相對濕度:百分之83% 
天氣:天色大致良好

3 則留言:

  1. 請問~ 用這個SPI的函示庫,這樣我街角可以更改? SCK、CS、SI、SO

    回覆刪除
  2. 在 PIC18F4550 的 SPI 硬件連接是已定好,SCK (RB1)、SDI (RB0)、SDO (RC7),但 CS (Chip Select) 是可以自由選擇。

    回覆刪除
  3. 你好 ~ 我有個問題想請問
    有兩塊相同的MCU 要進行SPI傳送和接收
    傳送端:
    void main()
    {
    Init_INTCON ();
    Init_GPIO ();
    Init_SPI();
    while(1)
    {
    for(int i = 0; i<256;i++)//讓LED從1開始亮
    {
    PORTD = i;
    spi_w(i);
    delay_ms(20);
    }
    }
    }
    unsigned char spi_w(unsigned char data)
    {
    SSPBUF = data; //start transmit
    while (!SSP1IF); //wait for transmission complete
    SSP1IF = 0;
    return(SSPBUF);
    }

    接收端 :
    void main()
    {
    Init_GPIO ();
    Init_SPI();
    Init_INTCON ();
    while(1)
    {
    data=spi_r();
    PORTD = data;
    }
    }
    unsigned char spi_r( void )
    {
    SSPBUF = 0x00; // initiate bus cycle
    while(!SSP1IF); // wait until cycle complete = while(SSP1IF==0)
    SSP1IF = 0;
    return ( SSPBUF ); // return with byte read
    }
    我想這樣應該會讓兩片板子的LED一起閃動
    但接收端LED沒反應 我有少加甚麼嗎(假設pin角有開 SPICON 也設定正確)

    回覆刪除