ATtiny88初体验(六):SPI
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 <stdint.h>
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <serial_stdio.h>
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("=================================\r\n");
// read device id of spi flash
uint8_t buf[8];
w25qxx_read_device_id(buf, 1);
printf("device id: 0x%02X.\r\n", buf[0]);
// read manufacturer and device id of spi flash
w25qxx_read_manufacturer_device_id(buf, 2);
printf("manufacturer & device id: 0x%02X%02X.\r\n", 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 < 8; i++) {
printf("%02X", buf[i]);
}
printf(".\r\n");
// read jedec id of spi flash
w25qxx_read_jedec_id(buf, 3);
printf("jedec id: 0x%02X%02X%02X.\r\n", buf[0], buf[1], buf[2]);
for (;;);
}
static void spi_setup(void)
{
// initialize gpios
// PB2 -> 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初体验(六):SPI的更多相关文章
- Spring Cloud Alibaba 初体验(六) Seata 及结合 MyBatis 与 MyBatis-Plus 的使用
一.下载与运行 本文使用 Seata 1.1.0:https://github.com/seata/seata/releases Windows 环境下双击 bin/seata-server.bat ...
- win7升win10,初体验
跟宿舍哥们聊着聊着,聊到最近发布正式版的win10,听网上各种评论,吐槽,撒花的,想想,倒不如自己升级一下看看,反正不喜欢还可以还原.于是就开始了win10的初体验了,像之前装黑苹果双系统一样的兴奋, ...
- ASP.NET2.0组件控件开发视频 初体验
原文:ASP.NET2.0组件控件开发视频 初体验 ASP.NET2.0组件控件开发视频 初体验 录了视频,质量不是很好,大家体验下.我会重新录制的 如果不清楚,可以看看http://v.youku. ...
- SpringBoot初体验及原理解析
一.前言 上篇文章,我们聊到了SpringBoot得以实现的幕后推手,这次我们来用SpringBoot开始HelloWorld之旅.SpringBoot是Spring框架对“约定大于配置(Conv ...
- ARKit从入门到精通(1)-ARKit初体验
ARKit从入门到精通(1)-ARKit初体验 转载自:http://blog.csdn.net/u013263917/article/details/72903174 该系列文章共十篇,笔者将由易到 ...
- Ignite缓存管理初体验
Ignite缓存管理初体验:ignite服务端配置,大家可以用参考官方进行配置(或者使用默认配置也可以). 本文中的ignite使用版本是1.7,与spring结合使用.maven依赖配置 ignit ...
- Node.js 网页瘸腿爬虫初体验
延续上一篇,想把自己博客的文档标题利用Node.js的request全提取出来,于是有了下面的初哥爬虫,水平有限,这只爬虫目前还有点瘸腿,请看官你指正了. // 内置http模块,提供了http服务器 ...
- 【全面解禁!真正的Expression Blend实战开发技巧】第七章 MVVM初体验-在DataGrid行末添加按钮
原文:[全面解禁!真正的Expression Blend实战开发技巧]第七章 MVVM初体验-在DataGrid行末添加按钮 博客更新较慢,先向各位读者说声抱歉.这一节讲解的依然是开发中经常遇到的一种 ...
- 【Python3爬虫】爬取美女图新姿势--Redis分布式爬虫初体验
一.写在前面 之前写的爬虫都是单机爬虫,还没有尝试过分布式爬虫,这次就是一个分布式爬虫的初体验.所谓分布式爬虫,就是要用多台电脑同时爬取数据,相比于单机爬虫,分布式爬虫的爬取速度更快,也能更好地应对I ...
- 【Python3爬虫】学习分布式爬虫第一步--Redis分布式爬虫初体验
一.写在前面 之前写的爬虫都是单机爬虫,还没有尝试过分布式爬虫,这次就是一个分布式爬虫的初体验.所谓分布式爬虫,就是要用多台电脑同时爬取数据,相比于单机爬虫,分布式爬虫的爬取速度更快,也能更好地应对I ...
随机推荐
- 代码随想录算法训练营Day44 动态规划
代码随想录算法训练营 代码随想录算法训练营Day44 动态规划|完全背包 518. 零钱兑换 II 377. 组合总和 Ⅳ 完全背包 有N件物品和一个最多能背重量为W的背包.第i件物品的重量是weig ...
- Netty实战(五)
一.什么是ByteBuf 我们前面说过,网络数据的基本单位总是字节.Java NIO 提供了 ByteBuffer 作为它的字节容器,但是这个类使用起来过于复杂,而且也有些繁琐.ByteBuffer ...
- CIO视角|平台工程带来的优势与机遇
在当今高速发展的技术环境中,企业越来越依赖技术作为创新和竞争优势的战略驱动力.首席信息官(CIO)在企业中负责监督信息和计算机技术的管理和实施,以交付预期的业务成果.在技术是业务核心的公司中,CIO ...
- pyinstaller打包exe
1.执行环境说明 python版本3.7直接使用pip进行安装pywin32.pyinstallerpip install pywin32pip install pyinstaller 2.使用了第三 ...
- LINIUX 查询命令的 区别 chich whereis locate fing
我们经常在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令来搜索: which 查看可执行文件的位置. whereis 查看文件的位置. locate 配合数据库查看文件位置 ...
- 第一单元 .Net 平台介绍
第一单元 .Net 平台介绍 学习编程,电脑基本配置(当然配置越高越好): 内存 :初期学习8 G,后期可能跟不上, 最好16 G以上 硬盘:500 G,5400 转速,至少C盘是固态,全是固态最好 ...
- std::aligned_alloc
定义于头文件 <cstdlib> (c++) void * aligned_alloc ( std::size_t alignment, std::size_t size); (c++17 ...
- 【技术积累】Linux中的基础知识【一】
Linux系统是什么 Linux系统是一种开源操作系统,它极具可定制性和灵活性,因此受到了许多人的欢迎.Linux系统以简单,强大和兼容性而著称.它可用于各种设备,从个人计算机到超级计算机,从移动设备 ...
- Spark SQL 及其DataFrame的基本操作
1.Spark SQL出现的 原因是什么? Spark SQL是Spark用来处理结构化数据的一个模块,它提供了一个叫作Data Frame的编程抽象结构数据模型(即带有Schema信息的RDD),S ...
- 驱动开发:内核远程线程实现DLL注入
在笔者上一篇文章<内核RIP劫持实现DLL注入>介绍了通过劫持RIP指针控制程序执行流实现插入DLL的目的,本章将继续探索全新的注入方式,通过NtCreateThreadEx这个内核函数实 ...