stm32的IIC和SPI协议及其实例
一、IIC协议和SPI协议
1.1 IIC(I2C)协议
I2C 通讯协议(Inter-Integrated Circuit)是由 Phiilps 公司开发的,由于它引脚少,硬件实现简单,可扩展性强,不需要 USART、CAN 等通讯协议的外部收发设备,现在被广泛地使用在系统内多个集成电路(IC)间的通讯。它是一个支持设备的总线。“总线”指多个设备共用的信号线。
在一个 I2C 通讯总线中,可连接多个 I2C 通讯设备,支持多个通讯主机及多个通讯从机。一个 I2C 总线只使用两条总线线路,一条双向串行数据线(SDA) ,一条串行时钟线(SCL)。数据线即用来表示数据,时钟线用于数据收发同步。每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问。总线通过上拉电阻接到电源。当 I2C 设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。具有三种传输模式:标准模式传输速率为 100kbit/s ,快速模式为 400kbit/s ,高速模式下可达 3.4Mbit/s,但目前大多 I2C 设备尚不支持高速模式。 连接到相同总线的 IC 数量受到总线的最大电容 400pF 限制 。
I2C 的所有硬件架构都是根据图中左侧 SCL 线和 SDA 线展开的STM32芯片有多个 I2C外设,它们的 I2C 通讯信号引出到不同的 GPIO 引脚上,使用时必须配置到这些指定的引脚。
起始信号产生后,所有从机就开始等待主机紧接下来 广播 的从机地址信号(SLAVE_ADDRESS)。在 I2C 总线上,每个设备的地址都是唯一的,当主机广播的地址与某个设备地址相同时,这个设备就被选中了,没被选中的设备将会忽略之后的数据信号。根据 I2C 协议,这个从机地址可以是 7 位或 10 位。在地址位之后,是传输方向的选择位,该位为 0 时,表示后面的数据传输方向是由主机传输至从机,即主机向从机写数据。该位为 1 时,则相反,即主机由从机读数据。从机接收到匹配的地址后,主机或从机会返回一个应答(ACK)或非应答(NACK)信号,只有接收到应答信号后,主机才能继续发送或接收数据。
1.2 SPI协议
SPI 协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface),即串行外围设备接口,是一种高速全双工的通信总线。它被广泛地使用在 ADC、LCD 等设备与 MCU 间,要求通讯速率较高的场合。
SPI 通讯设备之间的常用连接方式如下:
SPI 通讯使用 3 条总线及片选线,3 条总线分别为 SCK、MOSI、MISO,片选线为 SS,它们的作用介绍如下:
(1) SS( Slave Select):从设备选择信号线,常称为片选信号线,也称为 NSS、CS,以下用 NSS 表示。当有多个 SPI从设备与 SPI主机相连时,设备的其它信号线 SCK、MOSI及 MISO同时并联到相同的 SPI总线上,即无论有多少个从设备,都共同只使用这 3条
总线;而每个从设备都有独立的这一条 NSS 信号线,本信号线独占主机的一个引脚,即有多少个从设备,就有多少条片选信号线。I2C 协议中通过设备地址来寻址、选中总线上的某个设备并与其进行通讯;而 SPI 协议中没有设备地址,它使用 NSS 信号线来寻址,当主机要选择从设备时,把该从设备的 NSS 信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行 SPI通讯。所以 SPI通讯以 NSS 线置低电平为开始信号,以 NSS 线被拉高作为结束信号。
(2) SCK (Serial Clock):时钟信号线,用于通讯数据同步。它由通讯主机产生,决定了通讯的速率,不同的设备支持的最高时钟频率不一样,如 STM32 的 SPI 时钟频率最大为fpclk/2,两个设备之间通讯时,通讯速率受限于低速设备。
(3) MOSI (Master Output, Slave Input):主设备输出/从设备输入引脚。主机的数据从这条信号线输出,从机由这条信号线读入主机发送的数据,即这条线上数据的方向为主机
到从机。
(4) MISO(Master Input,,Slave Output):主设备输入/从设备输出引脚。主机从这条信号线读入数据,从机的数据由这条信号线输出到主机,即在这条线上数据的方向为从机到主机
SPI 的所有硬件架构都从图 25-5 中左侧 MOSI、MISO、SCK 及 NSS 线展开的。STM32芯片有多个 SPI 外设,它们的 SPI 通讯信号引出到不同的 GPIO 引脚上,使用时必须配置到这些指定的引脚。
二、 I2C协议下的温湿度检测
2.1 AHT20
AHT20是一种温湿度传感器,可以使用I2C接口。
有如下优点
- 高精度,完全校准
- 极高的可靠性与卓越的长期稳定性(较上一代aht10有极大的提升)
- 抗干扰能力强
- 性价比极高
- 适用于恶劣的环境条件下
引脚图如下
(需要注意的是,部分AHT20好像只能采用5v供电才能工作,不知道是不是实验使芯片本身的原因)
2.2代码部分
1.main函数,初始化相应模块
int main(void)
{
delay_init(); //延时函数初始化
uart_init(115200);
IIC_Init();
NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
while(1)
{
//printf("温度湿度显示");
read_AHT20_once();
}
}
2.设置AHT20工作模式
`
void read_AHT20_once(void)
{
delay_ms(10);
reset_AHT20();
delay_ms(10);
init_AHT20();
delay_ms(10);
startMeasure_AHT20();
delay_ms(80);
read_AHT20();
delay_ms(5);
}
3.读取AHT20发送的数据
void read_AHT20(void)
{
uint8_t i;
for(i=0; i<6; i++)
{
readByte[i]=0;
}
//-------------
I2C_Start();
I2C_WriteByte(0x71);
ack_status = Receive_ACK();
readByte[0]= I2C_ReadByte();
Send_ACK();
readByte[1]= I2C_ReadByte();
Send_ACK();
readByte[2]= I2C_ReadByte();
Send_ACK();
readByte[3]= I2C_ReadByte();
Send_ACK();
readByte[4]= I2C_ReadByte();
Send_ACK();
readByte[5]= I2C_ReadByte();
SendNot_Ack();
//Send_ACK();
I2C_Stop();
//--------------
if( (readByte[0] & 0x68) == 0x08 )
{
H1 = readByte[1];
H1 = (H1<<8) | readByte[2];
H1 = (H1<<8) | readByte[3];
H1 = H1>>4;
H1 = (H1*1000)/1024/1024;
T1 = readByte[3];
T1 = T1 & 0x0000000F;
T1 = (T1<<8) | readByte[4];
T1 = (T1<<8) | readByte[5];
T1 = (T1*2000)/1024/1024 - 500;
AHT20_OutData[0] = (H1>>8) & 0x000000FF;
AHT20_OutData[1] = H1 & 0x000000FF;
AHT20_OutData[2] = (T1>>8) & 0x000000FF;
AHT20_OutData[3] = T1 & 0x000000FF;
}
else
{
AHT20_OutData[0] = 0xFF;
AHT20_OutData[1] = 0xFF;
AHT20_OutData[2] = 0xFF;
AHT20_OutData[3] = 0xFF;
printf("lyy");
}
X printf("\r\n");
printf("温度:%d%d.%d",T1/100,(T1/10)%10,T1%10);
printf("湿度:%d%d.%d",H1/100,(H1/10)%10,H1%10);
printf("\r\n");
}
上述函数都可以厂家提供的数组包中找到,不需要自定义
完整代码如下提取码mwl4
2.3结果展示
温湿度和串口
可以看到,由于手握住温湿度传感器,温度在不断增高,最后两组数据湿度的
三、SPI协议和OLED显示屏
3.1OLED显示屏
OLED图示
特点如下
- 0.96寸OLED屏,支持黑白、黑蓝或者黄蓝双色显示
- 128x64分辨率,显示效果清晰,对比度高
- 超大可视角度:大于160°(显示屏中可视角度最大的一种屏幕)
- 宽电压供电(3V~5V),兼容3.3V和5V逻辑电平,无需电平转换芯片
- 默认为4线制SPI总线,可以选择3线制SPI总线或者IIC总线
- 超低功耗:正常显示仅为0.06W(远低于TFT显示屏)
- 军工级工艺标准,长期稳定工作
- 提供丰富的STM32、C51、Arduino、Raspberry Pi以及MSP430平台示例程序
- 提供底层驱动技术支持
引脚图如下
参考链接 http://www.lcdwiki.com/zh/0.96inch_SPI_OLED_Module
基础程序链接
3.2代码配置
1.下载上述链接程序
2.打开资料包,选择与自己平台相同的实例,打开Demo的工程(选择spi4线的),使用keil编译
3.更改部分函数,输出想要的结果
如果输出汉字,文件中的字符库可能没有,我们需要自己找到汉字对应的点阵(这里取16进制的)
我们输入“张三”后按下ctrl+enter
然后选择c51格式
生成的即为16进制的点阵
复制点阵后打开工程文件找到储存oled汉字模的头文件
如果没有看到的话可以右键单击hardware文件添加进来
把复制的数据加入数组
用自带的函数定义输出函数
void TEST_MainPage(void)
{
GUI_ShowCHinese(28,20,16,"江**",1);//中文姓名
GUI_ShowString(4,48,"6320730412",16,1);//数字详细
delay_ms(1500);
delay_ms(1500);
}
3.3结果展示
3.4改成滑动式展示方式
我们来输出点别的东西,我们希望输出的东西可以在屏幕上左右滑动,那该怎么办呢?
首先,还是要在字模库内添加新的汉字,具体步骤如下。
然后再main函数内添加下列代码就可以了
delay_init(); //延时函数初始化
NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
OLED_Init(); //初始化OLED
OLED_Clear(0); //清屏(全黑)
OLED_WR_Byte(0x2E,OLED_CMD); //关闭滚动
OLED_WR_Byte(0x27,OLED_CMD); //水平向左或者右滚动 26/27
OLED_WR_Byte(0x00,OLED_CMD); //虚拟字节
OLED_WR_Byte(0x00,OLED_CMD); //起始页 0
OLED_WR_Byte(0x07,OLED_CMD); //滚动时间间隔
OLED_WR_Byte(0x07,OLED_CMD); //终止页 7
OLED_WR_Byte(0x00,OLED_CMD); //虚拟字节
OLED_WR_Byte(0xFF,OLED_CMD); //虚拟字节
TEST_MainPage();
OLED_WR_Byte(0x2F,OLED_CMD); //开启滚动
}
3.5oled滑动显示结果展示
oled滑动
完整代码如下 提取码:nsae
四、结合:oled显示温湿度数据
有了前面两个例子做铺垫,我们现在把这两个例子结合起来,是不是就发现不是很难了。
再例一中,我们在read_AHT20()
函数中添加串口输出函数就达到了串口输出温湿度的效果,那么如果把这些函数改成输出到oled屏上不久可以了吗?
4.1改动例一代码
首先我们把例二代码的oled基本函数部分复制到例一工程去,如果建立了新的文件,不要忘记添加文件路径哦。
在read_AHT20()
函数中,我们把接受到的文件输入到数组中,然后再用oled的输出函数输出数组
sprintf(strTemp,"%.1f",a); //调用Sprintf函数把DHT11的温度数据格式化到字符串数组变量strTemp中
sprintf(strHumi,"%.1f",b); //调用Sprintf函数把DHT11的湿度数据格式化到字符串数组变量strHumi中
//printf(strTemp);
//printf("/r/n");
GUI_ShowCHinese(16,00,16,"温湿度显示",1);
GUI_ShowCHinese(16,20,16,"温度",1);
GUI_ShowString(53,20,strTemp,16,1);
GUI_ShowCHinese(16,38,16,"湿度",1);
GUI_ShowString(53,38,strHumi,16,1);
经过更改后,输出温湿度的途径就变成了oled屏了,我们编译烧录看下结果吧
完整代码如下:
数字取模软件提取码:ppmc
4.2结果展示
温湿度oled
五、总结
本次实验有一定的难度,但是网络上有相当齐全的参考资料,硬件厂家也提供了完善的库函数,需要注意的是在如此多的资料中筛选合适的代码。
六、参考链接
1.https://blog.csdn.net/qq_43279579/article/details/111414037
2.https://blog.csdn.net/hhhhhh277523/article/details/111397514
3.https://www.bilibili.com/video/BV1LB4y1A7ah/?spm_id_from=333.337.search-card.all.click
4http://www.lcdwiki.com/zh/0.96inch_SPI_OLED_Module