AVR的SPI接口很多只有一個,如果驅(qū)動較多的以SPI接口的外設時就必須通過IO來模擬,實際上對于低速外設來說IO模擬的方式也很方便,網(wǎng)上關于模擬SPI的程序很多,我的程序是基于GCCAVR來寫的,其他編譯器的都類似,寫的時候我盡量做到規(guī)范和方便后期使用時改動調(diào)整。
使用時需要注意以下幾點:
1、根據(jù)外設的時序要求,區(qū)分是在上升沿更新數(shù)據(jù)還是下降沿。
2、發(fā)送數(shù)據(jù)時高位在前還是地位在前。
3、外設對SPI通信有無速度要求,有些時候過快的通信速率可能無法讀取和寫入數(shù)據(jù)
4、CLK,數(shù)據(jù)等引腳的平時電平
上面幾點只要對照著外設的時序圖一眼就能弄清楚,程序里面寫的很清楚相應的改動一下就可以了。
程序如下:
/**************************(C) COPYRIGHT emouse 2011***************************
名稱:main.c
功能:模擬SPI程序測試
作者:emouse
時間:2011.1.11
版本:1.0
注意:無
*******************************************************************************/
#include"avr/io.h"
#include"avr/interrupt.h"
#include"util/delay.h"
#define SetBit(Port,N) (Port|=(1< #define ClrBit(Port,N) (Port&=~(1< #define ReverBit(Port,N) (Port^=(1< #define GetBit(Pin,N) ((Pin>>N)&0x01) //讀取IO某一位 /***************模擬SPI的相關宏定義********************/ #define SPI1_Port PORTC //設置使用的端口 #define SPI1_DDR DDRC #define SPI1_PIN PINC #define SPI1_CS 0 //設置每個信號對應的引腳 #define SPI1_MISO 1 #define SPI1_MOSI 2 #define SPI1_CLK 3 #define SPI1_CS_H (SPI1_Port|=(1< #define SPI1_CS_L (SPI1_Port&=~(1< #define SPI1_GetMISO ((SPI1_PIN>>SPI1_MISO)&0x01) #define SPI1_MOSI_H (SPI1_Port|=(1< #define SPI1_MOSI_L (SPI1_Port&=~(1< #define SPI1_CLK_H (SPI1_Port|=(1< #define SPI1_CLK_L (SPI1_Port&=~(1< unsigned char spi_delay; //設置信號的持續(xù)時間,相當于設置SPI的速度 /******************************************************************************* 名稱:void SPI1_Init() 功能:模擬SPI時序的端口初始化工作 參數(shù):無 時間:2011.1.11 版本:1.0 注意:無 *******************************************************************************/ void SPI1_Init() { SPI1_Port|=((1< SPI1_DDR|=(((1< SPI1_CS_H; SPI1_CLK_L; spi_delay=5; } /******************************************************************************* 名稱:SPI1_Send(unsigned char data) 功能:發(fā)送SPI數(shù)據(jù) 參數(shù):unsigned char data 時間:2011.1.11 版本:1.0 注意:無 *******************************************************************************/ void SPI1_Send(unsigned char data) { unsigned char i; SPI1_CS_L; //拉低片選信號 SPI1_CLK_L; //時鐘空閑時為低電平 SPI1_MOSI_L; _delay_us(spi_delay); for(i=0;i<8;i++) { if(data&(0x80>>i))//高位在前,低位在前改為(0x01< SPI1_MOSI_H; else SPI1_MOSI_L; _delay_us(spi_delay); SPI1_CLK_H; //在上升沿更新數(shù)據(jù) _delay_us(spi_delay); SPI1_CLK_L; } _delay_us(spi_delay); SPI1_CS_H; //拉高片選,完成一次數(shù)據(jù)傳輸 } /******************************************************************************* 名稱:unsigned char SPI1_Get() 功能:接收SPI數(shù)據(jù) 參數(shù):返回data 時間:2011.1.11 版本:1.0 注意:無 *******************************************************************************/ unsigned char SPI1_Get() { unsigned char i; unsigned char data=0x00; SPI1_CS_L; //拉低片選信號 SPI1_CLK_L; //時鐘空閑時為低電平 SPI1_MOSI_L; _delay_us(spi_delay); for(i=0;i<8;i++) { if(SPI1_GetMISO) data|=(0x80>>i); _delay_us(spi_delay); SPI1_CLK_H; //在上升沿更新數(shù)據(jù) _delay_us(spi_delay); SPI1_CLK_L; } _delay_us(spi_delay); SPI1_CS_H; //拉高片選,完成一次數(shù)據(jù)傳輸 return data; } /******************************************************************************* 名稱:void USART0_Init(void) 功能:串口0初始化 參數(shù):無 時間:2011.1.11 版本:1.0 注意:無 *******************************************************************************/ void USART0_Init(void) { UCSR0A=0x20; //波特率不加倍,單機通信模式 UCSR0B=0x18; //中斷不使能,允許發(fā)送和接收 UCSR0C=0x06;//異步模式,無校驗,8位數(shù)據(jù),1位停止位 UBRR0H=0x00; UBRR0L=51;//9600波特率 晶振8M } /******************************************************************************* 名稱:void USART0_Putc(unsigned char c) 功能:發(fā)送一個字符 參數(shù):unsigned char c 時間:2011.1.11 版本:1.0 注意:無 *******************************************************************************/ void USART0_Putc(unsigned char c) { while(!(UCSR0A&(1< UDR0=c; //發(fā)送數(shù)據(jù) } /******************************************************************************* 名稱:void USART0_Puts(unsigned char * str) 功能:發(fā)送字符串 參數(shù):unsigned char * str 待發(fā)送的字符串 時間:2011.1.11 版本:1.0 注意:無 *******************************************************************************/ void USART0_Puts(unsigned char * str) { while(*str) { USART0_Putc(*str++); } } int main(void) { unsigned char i=0; USART0_Init(); //初始化USART0接口 DDRA=0XFF; PORTA=0XFF; SPI1_Init(); USART0_Puts("SPI test"); while(1) { SPI1_Send(0x04); USART0_Putc(SPI1_Get()); ReverBit(PORTA,0); _delay_ms(500); } }