🚀write in front🚀
🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝💬本系列哔哩哔哩江科大STM32的视频为主以及自己的总结梳理📚
🚀Projeet source code🚀
💾工程代码放在了本人的Gitee仓库:iPickCan (iPickCan) - Gitee.com
引用:
STM32入门教程-2023版 细致讲解 中文字幕_哔哩哔哩_bilibili
Keil5 MDK版 下载与安装教程(STM32单片机编程软件)_mdk528-CSDN博客
STM32之Keil5 MDK的安装与下载_keil5下载程序到单片机stm32-CSDN博客
0. 江协科技/江科大-STM32入门教程-各章节详细笔记-查阅传送门-STM32标准库开发_江协科技stm32笔记-CSDN博客
【STM32】江科大STM32学习笔记汇总(已完结)_stm32江科大笔记-CSDN博客
江科大STM32学习笔记(上)_stm32博客-CSDN博客
STM32学习笔记一(基于标准库学习)_电平输出推免-CSDN博客
STM32 MCU学习资源-CSDN博客
stm32学习笔记-作者: Vera工程师养成记
stem32江科大自学笔记-CSDN博客
术语:
英文缩写 | 描述 |
GPIO:General Purpose Input Onuput | 通用输入输出 |
AFIO:Alternate Function Input Output | 复用输入输出 |
AO:Analog Output | 模拟输出 |
DO:Digital Output | 数字输出 |
内部时钟源 CK_INT:Clock Internal | 内部时钟源 |
外部时钟源 ETR:External Trigger | 时钟源 External 触发 |
外部时钟源 ETR:External Trigger mode 1 | 外部时钟源 External 触发 时钟模式1 |
外部时钟源 ETR:External Trigger mode 2 | 外部时钟源 External 触发 时钟模式2 |
外部时钟源 ITRx:Internal Trigger inputs | 外部时钟源,ITRx (Internal trigger inputs)内部触发输入 |
外部时钟源 TIx:exTernal Input pin | 外部时钟源 TIx (external input pin)外部输入引脚 |
CCR:Capture/Comapre Register | 捕获/比较寄存器 |
OC:Output Compare | 输出比较 |
IC:Input Capture | 输入捕获 |
TI1FP1:TI1 Filter Polarity 1 | Extern Input 1 Filter Polarity 1,外部输入1滤波极性1 |
TI1FP2:TI1 Filter Polarity 2 | Extern Input 1 Filter Polarity 2,外部输入1滤波极性2 |
DMA:Direct Memory Access | 直接存储器存取 |
正文:
0. 概述
从 2024/06/12 定下计划开始学习下江协科技STM32课程,接下来将会按照哔站上江协科技STM32的教学视频来学习入门STM32 开发,本文是视频教程 P2 STM32简介一讲的笔记。
感兴趣的一件事:
STM32HAL-最简单的长、短、多击按键框架
STM32HAL-最简单的长、短、多击按键框架(多按键)-CSDN博客
这就是一个简易的操作系统代码(瞎说的),基于时间片调度,没有抢占,但是有任务优先级。也就100行。
https://www.zhihu.com/question/658017543
1.🚚 软件SPI读写W25Q64
接线图
CS(片选)接到PA4 ,DO(从机输出)接到PA6 ,CLK时钟接到PA5 ,DI(从机输入)接到PA7,当然我这里引脚其实并不是任意选的,实际上是接到了硬件SPI的引脚上,这样的话软件SPI和硬件SPI都可以任意切换。
PA6为上拉输出入,PA4,PA5 ,PA7为推挽输出。
交换字节:W25Q64支持模式0和模式3,这里一般选择模式0。
程序的整体框架:
指令集:读取ID号时序:起始,先交换发送指令9F,随后连续交换接收3个字节,停止
第一个字节是厂商ID,后两个是设备ID,其中设备ID高8位,表示存储器类型,低8位表示容量。
- 💎第一个是写使能指令,发送一个指令码06
- 💎第二个是读状态寄存器1,作用是判断芯片是不是忙状态,要读取BUSY位,是否置1,1表示芯片在忙,0表示芯片不忙了。还要实现一个等待BUSY为0的函数,调用这个函数,BUSY为1,进入等待;BUSY为0,函数执行完毕。
- 💎第三个是页编程函数,先发送一个指令码02,再发3个字节的地址,最后发数据。
- 💎第四个扇区擦除,执行扇区擦除,先发送指令20,再发送3个字节的地址,这样指定地址,所在的扇区就会擦除。
最后一个读取数据,流程是:交换发送指令03,再发送3个字节的地址,随后转入接收,就可以依次接收数据
MySPI.c
#include "stm32f10x.h" // Device header
#include "MySPI.h"
void MySPI_W_SS(uint8_t bitValue)
{
GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)bitValue);
}
void MySPI_W_SCK(uint8_t bitValue)
{
GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)bitValue);
}
void MySPI_W_MOSI(uint8_t bitValue)
{
GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)bitValue);
}
uint8_t MySPI_R_MISO(void)
{
return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);
}
void MySPI_Init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef gpioInitStructure;
gpioInitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
gpioInitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
gpioInitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpioInitStructure);
gpioInitStructure.GPIO_Mode = GPIO_Mode_IPU;
gpioInitStructure.GPIO_Pin = GPIO_Pin_6;
gpioInitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpioInitStructure);
MySPI_W_SS(1);
MySPI_W_SCK(0); //use SPI mode0
}
void MySPI_Start(void)
{
MySPI_W_SS(0);
}
void MySPI_Stop(void)
{
MySPI_W_SS(1);
}
uint8_t MySPI_SwapByte(uint8_t byteSend)
{
uint8_t byteRecv = 0;
for(int i=0; i<8; i++)
{
MySPI_W_MOSI(byteSend & (0x80 >> i)); //SPI MOSI发送数据
MySPI_W_SCK(1); //SPI CLK上升沿
if(MySPI_R_MISO()) byteRecv |= (0x80 >> i); //SPI MISO读取数据
MySPI_W_SCK(0); //SPI下降沿
}
return byteRecv;
}
W25Q64.c
#include "stm32f10x.h" // Device header
#include "MySPI.h"
#include "W25Q64.h"
void W25Q64_Init(void)
{
MySPI_Init();
}
void W25Q64_ReadID(uint8_t *MID, uint16_t *DID)
{
uint8_t Data = 0;
MySPI_Start(); //SPI Start
MySPI_SwapByte(0x9F);
*MID = MySPI_SwapByte(0xFF);
Data = MySPI_SwapByte(0xFF);
Data = Data<< 8 | MySPI_SwapByte(0xFF);
*DID = Data;
MySPI_Stop(); //SPI Stop
}
Main.c
#include "stm32f10x.h" // Device header
#include "oled.h"
#include "Countersensor.h"
#include "Encoder.h"
#include "Timer.h"
#include "AD.h"
#include "Delay.h"
#include "MyDMA.h"
#include "UART.h"
#include <stdio.h>
#include "Key.h"
#include "String.h"
#include "LED.h"
#include "MyI2C.h"
#include "MP6050.h"
#include "MP6050_Reg.h"
#include "W25Q64.h"
uint8_t MID;
uint16_t DID;
int main(int argc, char *argv[])
{
OLED_Init();
W25Q64_Init();
W25Q64_ReadID(&MID, &DID);
OLED_ShowHexNum(1, 1, MID, 2);
OLED_ShowHexNum(1, 4, DID, 4);
while(1)
{
}
return 1;
}
💎现象
注意:写入数据前必须擦除,如不执行擦除,读出的数据=原始数据&写入的数据。