AVR的SPI接口很多只有一个,如果驱动较多的以SPI接口的外设时就必须通过IO来模拟,实际上对于低速外设来说IO模拟的方式也很方便,网上关于模拟SPI的程序很多,我的程序是基于GCCAVR来写的,其他编译器的都类似,写的时候我尽量做到规范和方便后期使用时改动调整。
使用时需要注意以下几点:
1、根据外设的时序要求,区分是在上升沿更新数据还是下降沿。
2、发送数据时高位在前还是地位在前。
3、外设对SPI通信有无速度要求,有些时候过快的通信速率可能无法读取和写入数据
4、CLK,数据等引脚的平时电平
上面几点只要对照着外设的时序图一眼就能弄清楚,程序里面写的很清楚相应的改动一下就可以了。
程序如下:
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
/**************************(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<<N)) //设置IO某一位
#define ClrBit(Port,N) (Port&=~(1<<N)) //清空IO某一位
#define ReverBit(Port,N) (Port^=(1<<N)) //取反IO某一位
#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<<SPI1_CS))
#define SPI1_CS_L (SPI1_Port&=~(1<<SPI1_CS))
#define SPI1_GetMISO ((SPI1_PIN>>SPI1_MISO)&0x01)
#define SPI1_MOSI_H (SPI1_Port|=(1<<SPI1_MOSI))
#define SPI1_MOSI_L (SPI1_Port&=~(1<<SPI1_MOSI))
#define SPI1_CLK_H (SPI1_Port|=(1<<SPI1_CLK))
#define SPI1_CLK_L (SPI1_Port&=~(1<<SPI1_CLK))
unsigned
char
spi_delay;
//设置信号的持续时间,相当于设置SPI的速度
/*******************************************************************************
名称:void SPI1_Init()
功能:模拟SPI时序的端口初始化工作
参数:无
时间:2011.1.11
版本:1.0
注意:无
*******************************************************************************/
void
SPI1_Init()
{
SPI1_Port|=((1<<SPI1_CS)|(1<<SPI1_MISO)|(1<<SPI1_MOSI)|(1<<SPI1_CLK));
SPI1_DDR|=(((1<<SPI1_CS)|(1<<SPI1_MOSI)|(1<<SPI1_CLK))&(~(1<<SPI1_MISO)));
SPI1_CS_H;
SPI1_CLK_L;
spi_delay=5;
}
/*******************************************************************************
名称:SPI1_Send(unsigned char data)
功能:发送SPI数据
参数: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<<i)
SPI1_MOSI_H;
else
SPI1_MOSI_L;
_delay_us(spi_delay);
SPI1_CLK_H;
//在上升沿更新数据
_delay_us(spi_delay);
SPI1_CLK_L;
}
_delay_us(spi_delay);
SPI1_CS_H;
//拉高片选,完成一次数据传输
}
/*******************************************************************************
名称:unsigned char SPI1_Get()
功能:接收SPI数据
参数:返回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;
//在上升沿更新数据
_delay_us(spi_delay);
SPI1_CLK_L;
}
_delay_us(spi_delay);
SPI1_CS_H;
//拉高片选,完成一次数据传输
return
data;
}
/*******************************************************************************
名称:void USART0_Init(void)
功能:串口0初始化
参数:无
时间:2011.1.11
版本:1.0
注意:无
*******************************************************************************/
void
USART0_Init(
void
)
{
UCSR0A=0x20;
//波特率不加倍,单机通信模式
UCSR0B=0x18;
//中断不使能,允许发送和接收
UCSR0C=0x06;
//异步模式,无校验,8位数据,1位停止位
UBRR0H=0x00;
UBRR0L=51;
//9600波特率 晶振8M
}
/*******************************************************************************
名称:void USART0_Putc(unsigned char c)
功能:发送一个字符
参数:unsigned char c
时间:2011.1.11
版本:1.0
注意:无
*******************************************************************************/
void
USART0_Putc(unsigned
char
c)
{
while
(!(UCSR0A&(1<<UDRE0)));
//等待发送缓冲空
UDR0=c;
//发送数据
}
/*******************************************************************************
名称:void USART0_Puts(unsigned char * str)
功能:发送字符串
参数:unsigned char * str 待发送的字符串
时间: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);
}
}
|
本文转自emouse博客园博客,原文链接:http://www.cnblogs.com/emouse/archive/2011/01/11/2198186.html,如需转载请自行联系原作者