ATtiny88初体验(六):SPI
SPI介绍
ATtiny88自带SPI模块,可以实现数据的全双工三线同步传输。它支持主从两种模式,可以配置为LSB或者MSB优先传输,有7种可编程速率,支持从空闲模式唤醒。
注意:为了使用SPI模块,必须将 PRR
寄存器中的 PRSPI
位设置为0。
ATtiny88的SPI时钟频率不能超过 (f_{OSC}/4) ,双倍速率模式下不能超过 (f_{OSC}/2) 。
当SPI使能时,MOSI、MISO、SCK、SS引脚的方向会被覆盖,具体见下表:
根据SCK的极性和相位不同,SPI分为四种模式:
寄存器
-
SPIE
:写入1使能SPI中断。 -
SPE
:写入1使能SPI。 -
DORD
:数据方向,写入1为LSB优先,写入0为MSB优先。 -
MSTR
:主机/从机模式选择,写入1为主机模式,写入0为从机模式。 -
CPOL
:时钟极性。 -
CPHA
:时钟相位。 -
SPR[1:0]
:SPI时钟速率选择。
-
SPIF
:SPI中断标志,执行完中断后自动清除,或者通过先读SPSR
寄存器,再访问SPDR
寄存器清除。 -
WCOL
:写冲突标志,在数据传输期间对SPDR
寄存器进行写操作时置位,通过先读SPSR
寄存器,再访问SPDR
寄存器清除。 -
SPI2X
:SPI速率加倍。在主机模式下,向此位写入1使SPI时钟速率加倍,最大速率为 (f_{OSC}/2) 。在从机模式下,最大速率还是只有 (f_{OSC}/4) 。
代码
下面的代码演示了使用ATtiny88的SPI模块与W25Q32 Flash模块进行通信,读取Flash的ID信息。源文件的组织结构如下:
.
├── Makefile
├── inc
│ ├── serial.h
│ └── serial_stdio.h
└── src
├── main.c
├── serial.c
└── serial_stdio.c
src/main.c
源文件的代码如下:
#include
#include
#include
#include
#include
static void spi_setup(void);
static uint8_t spi_read_and_write(uint8_t data);
static void w25qxx_read_device_id(void *id, uint8_t n);
static void w25qxx_read_manufacturer_device_id(void *id, uint8_t n);
static void w25qxx_read_unique_id(void *id, uint8_t n);
static void w25qxx_read_jedec_id(void *id, uint8_t n);
int main(void)
{
cli();
stdio_setup(); // initialize stdio and redirect it to serial
spi_setup(); // initialize spi module
sei();
printf("=================================rn");服务器托管网
// read device id of spi flash
uint8_t buf[8];
w25qxx_read_device_id(buf, 1);
printf("device id: 0x%02X.rn", buf[0]);
// read manufacturer and device id of spi flash
w25qxx_read_manufacturer_device_id(buf, 2);
printf("manufacturer & device id: 0x%02X%02X.rn", buf[0], buf[1]);
// read unique id of spi flash
w25qxx_read_unique_id(buf, 8);
printf("unique id: 0x");
for (uint8_t i = 0; i SS
// PB3 -> MOSI
// PB4 -> MISO
// PB5 -> SCK
DDRB |= _BV(DDB2) | _BV(DDB3) | _BV(DDB5);
PORTB |= _BV(PORTB2) | _BV(PORTB3) | _BV(PORTB5);
// enable spi, msb first, master mode, mode 3, prescaler = 64
SPCR = _BV(SPE) | _BV(MSTR) | _BV(CPOL) | _BV(CPHA) | _BV(SPR1) | _BV(SPR0);
SPSR = _BV(SPI2X);
}
static uint8_t spi_read_and_write(uint8_t data)
{
SPDR = data;
while (!(SPSR & _BV(SPIF)));
return SPDR;
}
static void w25qxx_read_device_id(void *id, uint8_t n)
{
if (n > 1) {
n = 1;
}
PORTB &= ~_BV(PORTB2);
spi_read_and_write(0xAB);
spi_read_and_write(0xFF);
spi_read_and_write(0xFF);
spi_read_and_write(0xFF);
while (n--) {
*(uint8_t *)id++ = spi_read_and_write(0xFF);
}
PORTB |= _BV(PORTB2);
}服务器托管网
static void w25qxx_read_manufacturer_device_id(void *id, uint8_t n)
{
if (n > 2) {
n = 2;
}
PORTB &= ~_BV(PORTB2);
spi_read_and_write(0x90);
spi_read_and_write(0xFF);
spi_read_and_write(0xFF);
spi_read_and_write(0x00);
while (n--) {
*(uint8_t *)id++ = spi_read_and_write(0xFF);
}
PORTB |= _BV(PORTB2);
}
static void w25qxx_read_unique_id(void *id, uint8_t n)
{
if (n > 8) {
n = 8;
}
PORTB &= ~_BV(PORTB2);
spi_read_and_write(0x4B);
spi_read_and_write(0xFF);
spi_read_and_write(0xFF);
spi_read_and_write(0xFF);
spi_read_and_write(0xFF);
while (n--) {
*(uint8_t *)id++ = spi_read_and_write(0xFF);
}
PORTB |= _BV(PORTB2);
}
static void w25qxx_read_jedec_id(void *id, uint8_t n)
{
if (n > 3) {
n = 3;
}
PORTB &= ~_BV(PORTB2);
spi_read_and_write(0x9F);
while (n--) {
*(uint8_t *)id++ = spi_read_and_write(0xFF);
}
PORTB |= _BV(PORTB2);
}
编译并下载程序到ATtiny88,连接好串口,可以观察串口的输出如下:
参考资料
- ATtiny88 Datasheet
- Programming and Interfacing ATMEL’s AVRs
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
相关推荐: 文字流光效果
一、html代码helloworld
二、css代码
总结提示:文字流光动画效果,炫酷标题 前言 提示:以下是本篇文章的代码内容,供大家参考,相互学习 一、html代码 好玩的聚光灯效果 helloworld 二、css代码 *{ /* 初始化 取消页面元素内外边距 */ margin: 0; padding: …