📄 main.c
字号:
/***********************************************
**** AVR SPI接口使用范例 ***
**** ***
**** 作者: HJJourAVR ***
**** 编译器:WINAVR20050214 ***
**** ***
**** www.OurAVR.com 2005.9.26 ***
***********************************************/
/*
本程序简单的示范了如何使用AVR ATMEGA16的SPI接口来访问DS1302 RTC实时时钟芯片
串行外设接口-SPI
DS1302的读写控制
USART跟PC连接,实现显示和控制
*/
#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
//时钟定为外部晶振 7.3728MHz,F_CPU=7372800
#include "main.h"
unsigned char DS1302_EXIST;
unsigned char INITDATE[8]={0x50, //59秒
0x59, //59分
0x23, //23时 24小时制
0x06, //06日
0x10, //10月
0x04, //星期四
0x05, //2005年
0x80 //写保护
};
unsigned char CURDATE[7];
unsigned char sCURDATE[]="20xx年xx月xx日xx时xx分xx秒 星期xx";
unsigned char sWEEK[]="错一二三四五六日";
//注意 汉字要占用2个字节的空间
int main(void)
{
//上电默认DDRx=0x00,PORTx=0x00 输入,无上拉电阻
PORTA=0xFF; //不用的管脚使能内部上拉电阻。
PORTC=0xFF;
PORTD=0xFF;
DDRD=(1<<PIN_TXD); //串口的输出
PORTB=~((1<<DS1302_CE)|(1<<DS1302_MOSI)|(1<<DS1302_MISO)|(1<<DS1302_SCK));
//DS1302带内部下拉电阻
DDRB =(1<<DS1302_CE)|(1<<DS1302_SCK)|(1<<DS1302_MOSI);
//设定SPI接口
init_USART();
init_SPI();
put_s("这是个简单的SPI接口访问DS1302实时时钟(RTC)的程序");
DS1302_EXIST=check_RTC(); //检测DS1302的存在
if(DS1302_EXIST)
{
put_s("按下[I]键可以初始化RTC时间,默认为2005年10月06日23时59分50秒 星期四");
put_s("按下[R]键可以读取当前时间");
put_s("用户可以自行开发其他功能");
put_s(" www.ouravr.com");
}
else
put_s("RTC找不到!");
sei(); //使能全局中断
while(1);
}
/*
串行外设接口-SPI
SPI接口可以令ATmega16 和外设或其他AVR器件进行高速的同步数据传输
ATmega16的SPI接口同时还用来实现程序和EEPROM的下载和上载。请参见[SPI串行编程和校验]。
SPI系统包括两个移位寄存器和一个主机时钟发生器。
主机和从机将需要发送的数据放入相应的移位寄存器。
主机在SCK 引脚上产生时钟脉冲以交换数据。
主机的数据从主机的MOSI 移出,从从机的MOSI 移入;从机的数据从从机的MISO 移出,从主机的MISO 移入
(其实就是由主机和从机构成一个16位的循环移位寄存器,所以收发数据是同时的,收发函数可以写成一条函数)
SPI系统的发送方向只有一个缓冲器,而在接收方向有两个缓冲器。
也就是说,在发送时一定要等到移位过程全部结束后才能对SPI 数据寄存器执行写操作。
而在接收数据时,需要在下一个字符移位过程结束之前通过访问SPI 数据寄存器读取当前接收到的字符。
否则第一个字节将丢失。
SS引脚的功能
1从机模式
从机模式当SPI配置为从机时,从机选择引脚SS总是为输入。
SS 为低将激活SPI 接口, MISO成为输出( 用户必须进行相应的端口配置) 引脚,其他引脚成为输入引脚。
当SS 为高时所有的引脚成为输入, SPI 逻辑复位,不再接收数据。
SS引脚对于数据包/字节的同步非常有用,可以使从机的位计数器与主机的时钟发生器同步。
当SS 拉高时SPI从机立即复位接收和发送逻辑,并丢弃移位寄存器里不完整的数据。
2主机模式
当SPI 配置为主机时(MSTR 的SPCR 置位),用户可以决定SS 引脚的方向。
若SS 配置为输出,则此引脚可以用作普通的I/O 口而不影响SPI 系统。典型应用是用来驱动从机的SS 引脚。
(单主机系统,SS引脚最好设成输出)
如果SS 配置为输入,必须保持为高以保证SPI 的正常工作。
若系统配置为主机, SS 为输入,但被外设拉低,则SPI 系统会将此低电平解释为有一个外部主机将自己选择为从机。
为了防止总线冲突, SPI 系统将实现如下动作:
1. 清零SPCR 的MSTR 位,使SPI 成为从机,从而MOSI 和SCK 变为输入。
2. SPSR 的SPIF 置位。若SPI 中断和全局中断开放,则中断服务程序将得到执行。
因此,使用中断方式处理SPI 主机的数据传输,并且存在SS 被拉低的可能性时,中断服务程序应该检查MSTR 是否为"1”。
若被清零,用户必须将其置位,以重新使能SPI 主机模式。
数据模式(中文手册有点混乱,请参考英文原版)
相对于串行数据, SCK的相位和极性有4种组合,由CPHA和CPOL控制组合的方式。
SPI模式 CPOL CPHA 起始沿 结束沿
0 0 0 采样(上升沿) 设置(下降沿)
1 0 1 设置(上升沿) 采样(下降沿)
2 1 0 采样(下降沿) 设置(上升沿)
3 1 1 设置(下降沿) 采样(上升沿)
SPI控制寄存器-SPCR
Bit 7 – SPIE: 使能SPI 中断
置位后,只要SPSR 寄存器的SPIF 和SREG 寄存器的全局中断使能位置位,就会引发SPI 中断。
Bit 6 – SPE: 使能SPI
SPE 置位将使能SPI。进行任何SPI 操作之前必须置位SPE。
Bit 5 – DORD: 数据次序
DORD 置位时数据的LSB 首先发送;否则数据的MSB 首先发送。
Bit 4 – MSTR: 主/ 从选择
MSTR置位时选择主机模式,否则为从机。
如果MSTR为"1”,SS配置为输入,但被拉低,则MSTR 被清零,寄存器SPSR 的SPIF 置位。
用户必须重新设置MSTR 进入主机模式
Bit 3 – CPOL: 时钟极性
CPOL 置位表示空闲时SCK 为高电平;否则空闲时SCK 为低电平。
Bit 2 – CPHA: 时钟相位
CPHA 决定数据是在SCK 的起始沿采样还是在SCK 的结束沿采样。
Bits 1, 0 – SPR1, SPR0: SPI 时钟速率选择1 与0
确定主机的SCK 速率。
SPR1 和SPR0 对从机没有影响。
SCK 和振荡器的时钟频率fosc关系如下表所示:
SPI2X SPR1 SPR0 SCK 频率
0 0 0 fosc/4
0 0 1 fosc/16
0 1 0 fosc/64
0 1 1 fosc/128
1 0 0 fosc/2
1 0 1 fosc/8
1 1 0 fosc/32
1 1 1 fosc/64
SPI状态寄存器-SPSR
Bit 7 – SPIF: SPI 中断标志
串行发送结束后,SPIF 置位。
若此时寄存器SPCR 的SPIE 和全局中断使能位置位,SPI中断即产生。
如果SPI 为主机, SS 配置为输入,且被拉低, SPIF 也将置位。
进入中断服务程序后SPIF自动清零。
或者可以通过先读SPSR,紧接着访问SPDR来对SPIF清零。
Bit 6 – WCOL: 写碰撞标志
在发送当中对SPI 数据寄存器SPDR写数据将置位WCOL。
WCOL可以通过先读SPSR,紧接着访问SPDR 来清零。
Bit 0 – SPI2X: SPI 倍速
置位后SPI 的速度加倍。
若为主机,则SCK 频率可达CPU 频率的一半。
若为从机,只能保证fosc /4。
SPI数据寄存器-SPDR
SPI数据寄存器为读/写寄存器,用来在寄存器文件和SPI移位寄存器之间传输数据。
写寄存器将启动数据传输,
读寄存器将读取寄存器的接收缓冲器。
*/
/*
DS1302的SPI接口特点:
1 I/O共用一个引脚,故M16的MOSI要串10K电阻到MISO,然后把MISO跟DS1302_IO脚短接在一起的
2 低位在先
3 SPI模式0 CPOL = 0, CPHA = 0,空闲时SCK为低电平,上升沿采样,下降沿设置
4 CE引脚为使能端,高电平使能SPI口
5 最高时钟速度 2MHz@Vcc=5V 500KHz@Vcc=2V
6 SCK/IO/CE都带有40K内部下拉电阻。
7 有写保护,写入数据前需要先去掉写保护。
8 BURST模式下对CLOCK进行写操作,必须一次写完8字节。
9 0x80地址的秒寄存器的第7位(CH)需要置0,震荡器才能起振.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -