赞
踩
最近要调STM32F1XX,想做个最小系统。手头的ARDUINO接口模块比较大。于是,我做了个STM32F103的ARDUINO接口的板子。
主控用的STM32F103RX(当然也可换成PIN2PIN的国产MCU),W25QXX,24C02,CH340串口,还引出个IIC OLED12864的接口。
用的是LCEDA画的,现在感觉是越来越好用了,我现在几乎放弃XD了。
废话不说,上图:原理图:
PCB图:
3D视图:
实物:
其中由于最近国外芯片价格暴涨,板上主要芯片均是国产(最近国产也不便宜了,GD32F103RC要90一片)。
在一家淘宝卖家店,求哥哥拜爷爷,人给了我一片STM32F103RCT6,要了35。这个价格在现在讲很不错了。
其中主要芯片:
STM32F103RCT6------->GD32F103RCT6
W25Q16 ------->BY26Q16
AT24C02 ------->BL24C02
设计时考虑外接的ARDUINO接口。板上已有外设尽量不占用ARDUINO接口。
其中24C02,由于想试验硬件IIC,使用了电阻来选通。具体如图:
如果焊接红框勾选的电阻,则占用PB6/PB7,此时与ARDUINO的IIC接口相连。
如果选用蓝框,则无影响,但这2脚无硬件IIC功能,只能软IIC。
板子设计时,考虑到运行RTT实时操作系统,特地选用大容量的STM32F103RCT6(FLASH:256K,RAM:64K),
而不使用小容量的STM32F103RBT6(FLASH:128K,RAM:20K)),并预留SD卡接口,挂载FATFS功能。
其中W25Q16 2MBYTE的FLASH用来存储字库及对应图片(由于空间2M不是很大,仅准备加载ASCII及宋体16)。
预留IIC接口的OLED,驱动OLED12864,可在上面运行简单的菜单系统或者轻量级的GUI。
板上有USB转串口CH340电路及USB DEVICE电路,可通过跳线帽,强制上拉D+,当然也可以通过引进控制。
设置初期,除了当普通开发板应用外。还兼任考虑ARDUINO,可刷入STM32F103RC ARDUINO底层固件,
并引出ISP下载控制按键。有兴趣的可以刷入ARDUINO固件,在STM32上面体验一把ARDUINO。
支持包请到rogerclarkmelbourne (Roger Clark) · GitHub上下载,该Git仓库中有两个我们需要下载的项目集,
分别是“Arduino_STM32-master”和“STM32duino-bootloader-master”。具体参考本篇**:
https://blog.csdn.net/argon_ghost/article/details/88297262
由于时间有限,这里本人并未具体尝试。
这里当做普通开发板使用,并调试了部分外设程序.
这里,如果之前写过W25Q16驱动的,对于BY25Q16而言,寄存器指令几乎一致,唯一不同的时ID:
具体指令表格:
我们把本例程中用到的对应ID,换成BY25Q16对应的。
- //定义B25Q16 ID 由规格书所得
-
- #<font color="#ff0000"><b>define B25Q16 0X6814</b></font>
-
-
-
- extern u16 W25QXX_TYPE; //
-
-
-
- #define W25QXX_CS PAout(8) //
-
-
-
-
-
- //BY25Q16对于寄存器一致
-
- #define W25X_WriteEnable 0x06
-
- #define W25X_WriteDisable 0x04
-
- #define W25X_ReadStatusReg 0x05
-
- #define W25X_WriteStatusReg 0x01
-
- #define W25X_ReadData 0x03
-
- #define W25X_FastReadData 0x0B
-
- #define W25X_FastReadDual 0x3B
-
- #define W25X_PageProgram 0x02
-
- #define W25X_BlockErase 0xD8
-
- #define W25X_SectorErase 0x20
-
- #define W25X_ChipErase 0xC7
-
- #define W25X_PowerDown 0xB9
-
- #define W25X_ReleasePowerDown 0xAB
-
- #define W25X_DeviceID 0xAB
-
- #define W25X_ManufactDeviceID 0x90
-
- #define W25X_JedecDeviceID 0x9F
-
-
-
- void W25QXX_Init(void);
-
- u16 W25QXX_ReadID(void); //
-
- u8 W25QXX_ReadSR(void); //
-
- void W25QXX_Write_SR(u8 sr); //
-
- void W25QXX_Write_Enable(void); //
-
- void W25QXX_Write_Disable(void); //
-
- void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);
-
- void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead); //
-
- void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);//
-
- void W25QXX_Erase_Chip(void); //
-
- void W25QXX_Erase_Sector(u32 Dst_Addr); //
-
- void W25QXX_Wait_Busy(void); //
-
- void W25QXX_PowerDown(void); //
-
- void W25QXX_WAKEUP(void); //

至于BL24C02则几乎完全一致,AT24C02的代码都无需修改:
具体地址定义及读写时序:
<blockquote>#include "24cxx.h"
着重说明,这里的SD卡用的是SPI模式,而不是SDIO模式:
本板中BY25Q16与SD共用SPI1,通过CS端切换使用:
- #include "sys.h"
-
- #include "mmc_sd.h"
-
- #include "spi.h"
-
- #include "usart.h"
-
-
-
- u8 SD_Type=0;//SD卡的类型
-
- 移植修改区///
-
- //移植时候的接口
-
- //data:要写入的数据
-
- //返回值:读到的数据
-
- u8 SD_SPI_ReadWriteByte(u8 data)
-
- {
-
- return SPI2_ReadWriteByte(data);
-
- }
-
- //SD卡初始化的时候,需要低速
-
- void SD_SPI_SpeedLow(void)
-
- {
-
- SPI2_SetSpeed(SPI_BaudRatePrescaler_256);//设置到低速模式
-
- }
-
- //SD卡正常工作的时候,可以高速了
-
- void SD_SPI_SpeedHigh(void)
-
- {
-
- SPI2_SetSpeed(SPI_BaudRatePrescaler_2);//设置到高速模式
-
- }
-
- //SPI硬件层初始化
-
- //FLASH_CS-->PA8
-
- //SD_CS-->PD2
-
- void SD_SPI_Init(void)
-
- {
-
- //设置硬件上与SD卡相关联的控制引脚输出
-
- //禁止其他外设(NRF/W25Q64)对SD卡产生影响
-
- //目前仅关在2个 B25Q16 及SD卡
-
-
-
- GPIO_InitTypeDef GPIO_InitStructure;
-
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE );//PORTB时钟使能
-
-
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; // PA8 推挽
-
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
-
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-
- GPIO_Init(GPIOA, &GPIO_InitStructure);
-
- GPIO_SetBits(GPIOA,GPIO_Pin_8);
-
-
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; // PD2 推挽
-
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
-
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-
- GPIO_Init(GPIOD, &GPIO_InitStructure);
-
- GPIO_SetBits(GPIOD,GPIO_Pin_2);
-
-
-
- SPI2_Init();
-
- SD_CS=1;
-
- }
-
- ///
-
- //取消选择,释放SPI总线
-
- void SD_DisSelect(void)
-
- {
-
- SD_CS=1;
-
- SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
-
- }
-
- //选择sd卡,并且等待卡准备OK
-
- //返回值:0,成功;1,失败;
-
- u8 SD_Select(void)
-
- {
-
- SD_CS=0;
-
- if(SD_WaitReady()==0)return 0;//等待成功
-
- SD_DisSelect();
-
- return 1;//等待失败
-
- }
-
- //等待卡准备好
-
- //返回值:0,准备好了;其他,错误代码
-
- u8 SD_WaitReady(void)
-
- {
-
- u32 t=0;
-
- do
-
- {
-
- if(SD_SPI_ReadWriteByte(0XFF)==0XFF)return 0;//OK
-
- t++;
-
- }while(t<0XFFFFFF);//等待
-
- return 1;
-
- }
-
- //等待SD卡回应
-
- //Response:要得到的回应值
-
- //返回值:0,成功得到了该回应值
-
- // 其他,得到回应值失败
-
- u8 SD_GetResponse(u8 Response)
-
- {
-
- u16 Count=0xFFFF;//等待次数
-
- while ((SD_SPI_ReadWriteByte(0XFF)!=Response)&&Count)Count--;//等待得到准确的回应
-
- if (Count==0)return MSD_RESPONSE_FAILURE;//得到回应失败
-
- else return MSD_RESPONSE_NO_ERROR;//正确回应
-
- }
-
- //从sd卡读取一个数据包的内容
-
- //buf:数据缓存区
-
- //len:要读取的数据长度.
-
- //返回值:0,成功;其他,失败;
-
- u8 SD_RecvData(u8*buf,u16 len)
-
- {
-
- if(SD_GetResponse(0xFE))return 1;//等待SD卡发回数据起始令牌0xFE
-
- while(len--)//开始接收数据
-
- {
-
- *buf=SPI2_ReadWriteByte(0xFF);
-
- buf++;
-
- }
-
- //下面是2个伪CRC(dummy CRC)
-
- SD_SPI_ReadWriteByte(0xFF);
-
- SD_SPI_ReadWriteByte(0xFF);
-
- return 0;//读取成功
-
- }
-
- //向sd卡写入一个数据包的内容 512字节
-
- //buf:数据缓存区
-
- //cmd:指令
-
- //返回值:0,成功;其他,失败;
-
- u8 SD_SendBlock(u8*buf,u8 cmd)
-
- {
-
- u16 t;
-
- if(SD_WaitReady())return 1;//等待准备失效
-
- SD_SPI_ReadWriteByte(cmd);
-
- if(cmd!=0XFD)//不是结束指令
-
- {
-
- for(t=0;t<512;t++)SPI2_ReadWriteByte(buf[t]);//提高速度,减少函数传参时间
-
- SD_SPI_ReadWriteByte(0xFF);//忽略crc
-
- SD_SPI_ReadWriteByte(0xFF);
-
- t=SD_SPI_ReadWriteByte(0xFF);//接收响应
-
- if((t&0x1F)!=0x05)return 2;//响应错误
-
- }
-
- return 0;//写入成功
-
- }
-
-
-
- //向SD卡发送一个命令
-
- //输入: u8 cmd 命令
-
- // u32 arg 命令参数
-
- // u8 crc crc校验值
-
- //返回值:SD卡返回的响应
-
- u8 SD_SendCmd(u8 cmd, u32 arg, u8 crc)
-
- {
-
- u8 r1;
-
- u8 Retry=0;
-
- SD_DisSelect();//取消上次片选
-
- if(SD_Select())return 0XFF;//片选失效
-
- //发送
-
- SD_SPI_ReadWriteByte(cmd | 0x40);//分别写入命令
-
- SD_SPI_ReadWriteByte(arg >> 24);
- SD_SPI_ReadWriteByte(arg >> 16);
- SD_SPI_ReadWriteByte(arg >> 8);
- SD_SPI_ReadWriteByte(arg);
-
- SD_SPI_ReadWriteByte(crc);
-
- if(cmd==CMD12)SD_SPI_ReadWriteByte(0xff);//Skip a stuff byte when stop reading
-
- //等待响应,或超时退出
-
- Retry=0X1F;
-
- do
-
- {
-
- r1=SD_SPI_ReadWriteByte(0xFF);
-
- }while((r1&0X80) && Retry--);
-
- //返回状态值
-
- return r1;
-
- }
-
- //获取SD卡的CID信息,包括制造商信息
-
- //输入: u8 *cid_data(存放CID的内存,至少16Byte)
-
- //返回值:0:NO_ERR
-
- // 1:错误
-
- u8 SD_GetCID(u8 *cid_data)
-
- {
-
- u8 r1;
-
- //发CMD10命令,读CID
-
- r1=SD_SendCmd(CMD10,0,0x01);
-
- if(r1==0x00)
-
- {
-
- r1=SD_RecvData(cid_data,16);//接收16个字节的数据
-
- }
-
- SD_DisSelect();//取消片选
-
- if(r1)return 1;
-
- else return 0;
-
- }
-
- //获取SD卡的CSD信息,包括容量和速度信息
-
- //输入:u8 *cid_data(存放CID的内存,至少16Byte)
-
- //返回值:0:NO_ERR
-
- // 1:错误
-
- u8 SD_GetCSD(u8 *csd_data)
-
- {
-
- u8 r1;
-
- r1=SD_SendCmd(CMD9,0,0x01);//发CMD9命令,读CSD
-
- if(r1==0)
-
- {
-
- r1=SD_RecvData(csd_data, 16);//接收16个字节的数据
-
- }
-
- SD_DisSelect();//取消片选
-
- if(r1)return 1;
-
- else return 0;
-
- }
-
- //获取SD卡的总扇区数(扇区数)
-
- //返回值:0: 取容量出错
-
- // 其他:SD卡的容量(扇区数/512字节)
-
- //每扇区的字节数必为512,因为如果不是512,则初始化不能通过.
-
- u32 SD_GetSectorCount(void)
-
- {
-
- u8 csd[16];
-
- u32 Capacity;
-
- u8 n;
-
- u16 csize;
-
- //取CSD信息,如果期间出错,返回0
-
- if(SD_GetCSD(csd)!=0) return 0;
-
- //如果为SDHC卡,按照下面方式计算
-
- if((csd[0]&0xC0)==0x40) //V2.00的卡
-
- {
-
- csize = csd[9] + ((u16)csd[8] << 8) + 1;
-
- Capacity = (u32)csize << 10;//得到扇区数
-
- }else//V1.XX的卡
-
- {
-
- n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
- csize = (csd[8] >> 6) + ((u16)csd[7] << 2) + ((u16)(csd[6] & 3) << 10) + 1;
- Capacity= (u32)csize << (n - 9);//得到扇区数
-
- }
-
- return Capacity;
-
- }
-
- //初始化SD卡
-
- u8 SD_Initialize(void)
-
- {
-
- u8 r1; // 存放SD卡的返回值
-
- u16 retry; // 用来进行超时计数
-
- u8 buf[4];
-
- u16 i;
-
-
-
- SD_SPI_Init(); //初始化IO
-
- SD_SPI_SpeedLow(); //设置到低速模式
-
- for(i=0;i<10;i++)SD_SPI_ReadWriteByte(0XFF);//发送最少74个脉冲
-
- retry=20;
-
- do
-
- {
-
- r1=SD_SendCmd(CMD0,0,0x95);//进入IDLE状态
-
- }while((r1!=0X01) && retry--);
-
- SD_Type=0;//默认无卡
-
- if(r1==0X01)
-
- {
-
- if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
-
- {
-
- for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF); //Get trailing return value of R7 resp
-
- if(buf[2]==0X01&&buf[3]==0XAA)//卡是否支持2.7~3.6V
-
- {
-
- retry=0XFFFE;
-
- do
-
- {
-
- SD_SendCmd(CMD55,0,0X01); //发送CMD55
-
- r1=SD_SendCmd(CMD41,0x40000000,0X01);//发送CMD41
-
- }while(r1&&retry--);
-
- if(retry&&SD_SendCmd(CMD58,0,0X01)==0)//鉴别SD2.0卡版本开始
-
- {
-
- for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);//得到OCR值
-
- if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC; //检查CCS
-
- else SD_Type=SD_TYPE_V2;
-
- }
-
- }
-
- }else//SD V1.x/ MMC V3
-
- {
-
- SD_SendCmd(CMD55,0,0X01); //发送CMD55
-
- r1=SD_SendCmd(CMD41,0,0X01); //发送CMD41
-
- if(r1<=1)
-
- {
-
- SD_Type=SD_TYPE_V1;
-
- retry=0XFFFE;
-
- do //等待退出IDLE模式
-
- {
-
- SD_SendCmd(CMD55,0,0X01); //发送CMD55
-
- r1=SD_SendCmd(CMD41,0,0X01);//发送CMD41
-
- }while(r1&&retry--);
-
- }else//MMC卡不支持CMD55+CMD41识别
-
- {
-
- SD_Type=SD_TYPE_MMC;//MMC V3
-
- retry=0XFFFE;
-
- do //等待退出IDLE模式
-
- {
-
- r1=SD_SendCmd(CMD1,0,0X01);//发送CMD1
-
- }while(r1&&retry--);
-
- }
-
- if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)SD_Type=SD_TYPE_ERR;//错误的卡
-
- }
-
- }
-
- SD_DisSelect();//取消片选
-
- SD_SPI_SpeedHigh();//高速
-
- if(SD_Type)return 0;
-
- else if(r1)return r1;
-
- return 0xaa;//其他错误
-
- }
-
- //读SD卡
-
- //buf:数据缓存区
-
- //sector:扇区
-
- //cnt:扇区数
-
- //返回值:0,ok;其他,失败.
-
- u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt)
-
- {
-
- u8 r1;
-
- if(SD_Type!=SD_TYPE_V2HC)sector <<= 9;//转换为字节地址
-
- if(cnt==1)
-
- {
-
- r1=SD_SendCmd(CMD17,sector,0X01);//读命令
-
- if(r1==0)//指令发送成功
-
- {
-
- r1=SD_RecvData(buf,512);//接收512个字节
-
- }
-
- }else
-
- {
-
- r1=SD_SendCmd(CMD18,sector,0X01);//连续读命令
-
- do
-
- {
-
- r1=SD_RecvData(buf,512);//接收512个字节
-
- buf+=512;
-
- }while(--cnt && r1==0);
-
- SD_SendCmd(CMD12,0,0X01); //发送停止命令
-
- }
-
- SD_DisSelect();//取消片选
-
- return r1;//
-
- }
-
- //写SD卡
-
- //buf:数据缓存区
-
- //sector:起始扇区
-
- //cnt:扇区数
-
- //返回值:0,ok;其他,失败.
-
- u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt)
-
- {
-
- u8 r1;
-
- if(SD_Type!=SD_TYPE_V2HC)sector *= 512;//转换为字节地址
-
- if(cnt==1)
-
- {
-
- r1=SD_SendCmd(CMD24,sector,0X01);//读命令
-
- if(r1==0)//指令发送成功
-
- {
-
- r1=SD_SendBlock(buf,0xFE);//写512个字节
-
- }
-
- }else
-
- {
-
- if(SD_Type!=SD_TYPE_MMC)
-
- {
-
- SD_SendCmd(CMD55,0,0X01);
-
- SD_SendCmd(CMD23,cnt,0X01);//发送指令
-
- }
-
- r1=SD_SendCmd(CMD25,sector,0X01);//连续读命令
-
- if(r1==0)
-
- {
-
- do
-
- {
-
- r1=SD_SendBlock(buf,0xFC);//接收512个字节
-
- buf+=512;
-
- }while(--cnt && r1==0);
-
- r1=SD_SendBlock(0,0xFD);//接收512个字节
-
- }
-
- }
-
- SD_DisSelect();//取消片选
-
- return r1;//
-
- }
-
-
-
- //SD test
-
- //#include "malloc.h"
-
-
-
- //读取SD卡的指定扇区的内容,并通过串口1输出
-
- sec:扇区物理地址编号
-
- //void SD_Read_Sectorx(u32 sec)
-
- //{
-
- // u8 *buf;
-
- // u16 i;
-
- // buf=mymalloc(512); //申请内存
-
- // if(SD_ReadDisk(buf,sec,1)==0) //读取0扇区的内容
-
- // {
-
- // LCD_ShowString(60,190,200,16,16,"USART1 Sending Data...");
-
- // printf("SECTOR 0 DATA:\r\n");
-
- // for(i=0;i<512;i++)printf("%x ",buf[i]);//打印sec扇区数据
-
- // printf("\r\nDATA ENDED\r\n");
-
- // LCD_ShowString(60,190,200,16,16,"USART1 Send Data Over!");
-
- // }
-
- // myfree(buf);//释放内存
-
- //}
-
-
-

另MCU中的硬件IIC引脚均接了上拉,以防外接模块没有加。
对于OLED12864,就没什么好说的了,直接模拟IIC驱动:
- #include "oled.h"
-
- #include "stdlib.h"
-
- #include "oledfont.h"
-
- #include "delay.h"
-
-
-
- u8 OLED_GRAM[144][8];
-
-
-
-
-
-
-
- 具体IIC控制函数
-
- //起始信号
-
- static void I2C_Start(void)
-
- {
-
- OLED_SDIN_Set();
-
- OLED_SCLK_Set();
-
- OLED_SDIN_Clr();
-
- OLED_SCLK_Clr();
-
- }
-
-
-
- //结束信号
-
- static void I2C_Stop(void)
-
- {
-
- OLED_SCLK_Set();
-
- OLED_SDIN_Clr();
-
- OLED_SDIN_Set();
-
- }
-
-
-
- //等待信号响应
-
- static void I2C_WaitAck(void) //测数据信号的电平
-
- {
-
- OLED_SCLK_Set();
-
- OLED_SCLK_Clr();
-
- }
-
-
-
- //写入一个字节
-
- static void Send_Byte(u8 dat)
-
- {
-
- u8 i;
-
- for(i=0;i<8;i++)
-
- {
-
- OLED_SCLK_Clr();//将时钟信号设置为低电平
-
- if(dat&0x80)//将dat的8位从最高位依次写入
-
- {
-
- OLED_SDIN_Set();
-
- }
-
- else
-
- {
-
- OLED_SDIN_Clr();
-
- }
-
- OLED_SCLK_Set();//将时钟信号设置为高电平
-
- OLED_SCLK_Clr();//将时钟信号设置为低电平
-
- dat<<=1;
-
- }
-
- }
-
-
-
- //发送一个字节
-
- //向SSD1306写入一个字节。
-
- //mode:数据/命令标志 0,表示命令;1,表示数据;
-
- void OLED_WR_Byte(u8 dat,u8 mode)
-
- {
-
- I2C_Start();
-
- Send_Byte(0x78);
-
- I2C_WaitAck();
-
- if(mode){Send_Byte(0x40);}
-
- else{Send_Byte(0x00);}
-
- I2C_WaitAck();
-
- Send_Byte(dat);
-
- I2C_WaitAck();
-
- I2C_Stop();
-
- }
-
-
-
-
-
- //反显函数
-
- void OLED_ColorTurn(u8 i)
-
- {
-
- if(i==0)
-
- {
-
- OLED_WR_Byte(0xA6,OLED_CMD);//正常显示
-
- }
-
- if(i==1)
-
- {
-
- OLED_WR_Byte(0xA7,OLED_CMD);//反色显示
-
- }
-
- }
-
-
-
- //屏幕旋转180度
-
- void OLED_DisplayTurn(u8 i)
-
- {
-
- if(i==0)
-
- {
-
- OLED_WR_Byte(0xC8,OLED_CMD);//正常显示
-
- OLED_WR_Byte(0xA1,OLED_CMD);
-
- }
-
- if(i==1)
-
- {
-
- OLED_WR_Byte(0xC0,OLED_CMD);//反转显示
-
- OLED_WR_Byte(0xA0,OLED_CMD);
-
- }
-
- }
-
-
-
-
-
- //开启OLED显示
-
- void OLED_DisPlay_On(void)
-
- {
-
- OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能
-
- OLED_WR_Byte(0x14,OLED_CMD);//开启电荷泵
-
- OLED_WR_Byte(0xAF,OLED_CMD);//点亮屏幕
-
- }
-
-
-
- //关闭OLED显示
-
- void OLED_DisPlay_Off(void)
-
- {
-
- OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能
-
- OLED_WR_Byte(0x10,OLED_CMD);//关闭电荷泵
-
- OLED_WR_Byte(0xAF,OLED_CMD);//关闭屏幕
-
- }
-
-
-
- //更新显存到OLED
-
- void OLED_Refresh(void)
-
- {
-
- u8 i,n;
-
- for(i=0;i<8;i++)
-
- {
-
- OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址
-
- OLED_WR_Byte(0x00,OLED_CMD); //设置低列起始地址
-
- OLED_WR_Byte(0x10,OLED_CMD); //设置高列起始地址
-
- for(n=0;n<128;n++)
-
- OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA);
-
- }
-
- }
-
- //自定义清屏函数
-
- void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2)
-
- {
-
- u8 i,n;
-
- for(i=y1;i<y2;i++)
-
- {
-
- for(n=x1;n<x2;n++)
-
- {
-
- OLED_GRAM[n][i]=0;//清除所有数据
-
- }
-
- }
-
- OLED_Refresh();//更新显示
-
- }
-
- //清屏函数
-
- void OLED_Clear(void)
-
- {
-
- u8 i,n;
-
- for(i=0;i<8;i++)
-
- {
-
- for(n=0;n<128;n++)
-
- {
-
- OLED_GRAM[n][i]=0;//清除所有数据
-
- }
-
- }
-
- OLED_Refresh();//更新显示
-
- }
-
-
-
- //画点
-
- //x:0~127
-
- //y:0~63
-
- void OLED_DrawPoint(u8 x,u8 y)
-
- {
-
- u8 i,m,n;
-
- i=y/8;
-
- m=y%8;
-
- n=1<<m;
-
- OLED_GRAM[x][i]|=n;
-
- }
-
-
-
- //清除一个点
-
- //x:0~127
-
- //y:0~63
-
- void OLED_ClearPoint(u8 x,u8 y)
-
- {
-
- u8 i,m,n;
-
- i=y/8;
-
- m=y%8;
-
- n=1<<m;
-
- OLED_GRAM[x][i]=~OLED_GRAM[x][i];
-
- OLED_GRAM[x][i]|=n;
-
- OLED_GRAM[x][i]=~OLED_GRAM[x][i];
-
- }
-
-
-
-
-
- //画线
-
- //x:0~128
-
- //y:0~64
-
- void OLED_DrawLine(u8 x1,u8 y1,u8 x2,u8 y2)
-
- {
-
- u8 i,k,k1,k2;
-
- if((1)||(x2>128)||(1)||(y2>64)||(x1>x2)||(y1>y2))return;
-
- if(x1==x2) //画竖线
-
- {
-
- for(i=0;i<(y2-y1);i++)
-
- {
-
- OLED_DrawPoint(x1,y1+i);
-
- }
-
- }
-
- else if(y1==y2) //画横线
-
- {
-
- for(i=0;i<(x2-x1);i++)
-
- {
-
- OLED_DrawPoint(x1+i,y1);
-
- }
-
- }
-
- else //画斜线
-
- {
-
- k1=y2-y1;
-
- k2=x2-x1;
-
- k=k1*10/k2;
-
- for(i=0;i<(x2-x1);i++)
-
- {
-
- OLED_DrawPoint(x1+i,y1+i*k/10);
-
- }
-
- }
-
- }
-
- //x,y:圆心坐标
-
- //r:圆的半径
-
- void OLED_DrawCircle(u8 x,u8 y,u8 r)
-
- {
-
- int a, b,num;
-
- a = 0;
-
- b = r;
-
- while(2 * b * b >= r * r)
-
- {
-
- OLED_DrawPoint(x + a, y - b);
-
- OLED_DrawPoint(x - a, y - b);
-
- OLED_DrawPoint(x - a, y + b);
-
- OLED_DrawPoint(x + a, y + b);
-
-
-
- OLED_DrawPoint(x + b, y + a);
-
- OLED_DrawPoint(x + b, y - a);
-
- OLED_DrawPoint(x - b, y - a);
-
- OLED_DrawPoint(x - b, y + a);
-
-
-
- a++;
-
- num = (a * a + b * b) - r*r;//计算画的点离圆心的距离
-
- if(num > 0)
-
- {
-
- b--;
-
- a--;
-
- }
-
- }
-
- }
-
-
-
-
-
-
-
- //在指定位置显示一个字符,包括部分字符
-
- //x:0~127
-
- //y:0~63
-
- //size:选择字体 12/16/24
-
- void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size1)
-
- {
-
- u8 i,m,temp,size2,chr1;
-
- u8 y0=y;
-
- size2=(size1/8+((size1%8)?1:0))*(size1/2); //得到字体一个字符对应点阵集所占的字节数
-
- chr1=chr-' '; //计算偏移后的值
-
- for(i=0;i<size2;i++)
-
- {
-
- if(size1==12)
-
- {temp=asc2_1206[chr1][i];} //调用1206字体
-
- else if(size1==16)
-
- {temp=asc2_1608[chr1][i];} //调用1608字体
-
- else if(size1==24)
-
- {temp=asc2_2412[chr1][i];} //调用2412字体
-
- else return;
-
- for(m=0;m<8;m++) //写入数据
-
- {
-
- if(temp&0x80)OLED_DrawPoint(x,y);
-
- else OLED_ClearPoint(x,y);
-
- temp<<=1;
-
- y++;
-
- if((y-y0)==size1)
-
- {
-
- y=y0;
-
- x++;
-
- break;
-
- }
-
- }
-
- }
-
- }
-
-
-
-
-
- //显示字符串
-
- //x,y:起点坐标
-
- //size1:字体大小
-
- //*chr:字符串起始地址
-
- void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 size1)
-
- {
-
- while((*chr>=' ')&&(*chr<='~'))//判断是不是非法字符!
-
- {
-
- OLED_ShowChar(x,y,*chr,size1);
-
- x+=size1/2;
-
- if(x>128-size1) //换行
-
- {
-
- x=0;
-
- y+=2;
-
- }
-
- chr++;
-
- }
-
- }
-
-
-
- //m^n
-
- u32 OLED_Pow(u8 m,u8 n)
-
- {
-
- u32 result=1;
-
- while(n--)
-
- {
-
- result*=m;
-
- }
-
- return result;
-
- }
-
-
-
- 显示2个数字
-
- x,y :起点坐标
-
- len :数字的位数
-
- size:字体大小
-
- void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size1)
-
- {
-
- u8 t,temp;
-
- for(t=0;t<len;t++)
-
- {
-
- temp=(num/OLED_Pow(10,len-t-1))%10;
-
- if(temp==0)
-
- {
-
- OLED_ShowChar(x+(size1/2)*t,y,'0',size1);
-
- }
-
- else
-
- {
-
- OLED_ShowChar(x+(size1/2)*t,y,temp+'0',size1);
-
- }
-
- }
-
- }
-
-
-
- //显示汉字
-
- //x,y:起点坐标
-
- //num:汉字对应的序号
-
- void OLED_ShowChinese(u8 x,u8 y,u8 num,u8 size1)
-
- {
-
- u8 i,m,n=0,temp,chr1;
-
- u8 x0=x,y0=y;
-
- u8 size3=size1/8;
-
- while(size3--)
-
- {
-
- chr1=num*size1/8+n;
-
- n++;
-
- for(i=0;i<size1;i++)
-
- {
-
- if(size1==16)
-
- {temp=Hzk1[chr1][i];}//调用16*16字体
-
- else if(size1==24)
-
- {temp=Hzk2[chr1][i];}//调用24*24字体
-
- else if(size1==32)
-
- {temp=Hzk3[chr1][i];}//调用32*32字体
-
- else if(size1==64)
-
- {temp=Hzk4[chr1][i];}//调用64*64字体
-
- else return;
-
-
-
- for(m=0;m<8;m++)
-
- {
-
- if(temp&0x01)OLED_DrawPoint(x,y);
-
- else OLED_ClearPoint(x,y);
-
- temp>>=1;
- y++;
-
- }
-
- x++;
-
- if((x-x0)==size1)
-
- {x=x0;y0=y0+8;}
-
- y=y0;
-
- }
-
- }
-
- }
-
-
-
- //num 显示汉字的个数
-
- //space 每一遍显示的间隔
-
- void OLED_ScrollDisplay(u8 num,u8 space)
-
- {
-
- u8 i,n,t=0,m=0,r;
-
- while(1)
-
- {
-
- if(m==0)
-
- {
-
- OLED_ShowChinese(128,24,t,16); //写入一个汉字保存在OLED_GRAM[][]数组中
-
- t++;
-
- }
-
- if(t==num)
-
- {
-
- for(r=0;r<16*space;r++) //显示间隔
-
- {
-
- for(i=0;i<144;i++)
-
- {
-
- for(n=0;n<8;n++)
-
- {
-
- OLED_GRAM[i-1][n]=OLED_GRAM[i][n];
-
- }
-
- }
-
- OLED_Refresh();
-
- }
-
- t=0;
-
- }
-
- m++;
-
- if(m==16){m=0;}
-
- for(i=0;i<144;i++) //实现左移
-
- {
-
- for(n=0;n<8;n++)
-
- {
-
- OLED_GRAM[i-1][n]=OLED_GRAM[i][n];
-
- }
-
- }
-
- OLED_Refresh();
-
- }
-
- }
-
-
-
- //配置写入数据的起始位置
-
- void OLED_WR_BP(u8 x,u8 y)
-
- {
-
- OLED_WR_Byte(0xb0+y,OLED_CMD);//设置行起始地址
-
- OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
- OLED_WR_Byte((x&0x0f)|0x01,OLED_CMD);
-
- }
-
-
-
- //x0,y0:起点坐标
-
- //x1,y1:终点坐标
-
- //BMP[]:要写入的图片数组
-
- void OLED_ShowPicture(u8 x0,u8 y0,u8 x1,u8 y1,u8 BMP[])
-
- {
-
- u32 j=0;
-
- u8 x=0,y=0;
-
- if(y%8==0)y=0;
-
- else y+=1;
-
- for(y=y0;y<y1;y++)
-
- {
-
- OLED_WR_BP(x0,y);
-
- for(x=x0;x<x1;x++)
-
- {
-
- OLED_WR_Byte(BMP[j],OLED_DATA);
-
- j++;
-
- }
-
- }
-
- }
-
- //OLED的初始化
-
- void OLED_Init(void)
-
- {
-
- GPIO_InitTypeDef GPIO_InitStructure;
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //使能C端口时钟
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5;
-
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
-
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
-
- GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化GPIOC4,5
-
- GPIO_SetBits(GPIOC,GPIO_Pin_4|GPIO_Pin_5);
-
-
-
- delay_ms(200);
-
-
-
- OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
-
- OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
-
- OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
-
- OLED_WR_Byte(0x40,OLED_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
-
- OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
-
- OLED_WR_Byte(0xCF,OLED_CMD);// Set SEG Output Current Brightness
-
- OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
-
- OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
-
- OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
-
- OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
-
- OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
-
- OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
-
- OLED_WR_Byte(0x00,OLED_CMD);//-not offset
-
- OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
-
- OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
-
- OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
-
- OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
-
- OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
-
- OLED_WR_Byte(0x12,OLED_CMD);
-
- OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
-
- OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
-
- OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
-
- OLED_WR_Byte(0x02,OLED_CMD);//
-
- OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
-
- OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
-
- OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
-
- OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
-
- OLED_WR_Byte(0xAF,OLED_CMD);
-
- OLED_Clear();
-
- }

目前仅对几个外设底层驱动进行了编写调试,下面准备上RTT并FATFS。
在main函数中调用:
- //OLED
-
- OLED_Init();
-
- OLED_ShowString(40,0,(u8*)"MPU6050",16);
-
- OLED_Refresh();
-
- //24CXX
-
- AT24CXX_Init(); //IIC初始化
-
- while(AT24CXX_Check())//检测不到24c02
-
- {
-
- OLED_ShowString(0,16,(u8*)"24C04 Check Failed!",16);
-
- delay_ms(500);
-
- OLED_ShowString(0,32,(u8*)"Please Check! ",16);
-
- delay_ms(500);
-
- LED0=!LED0;//DS0闪烁
-
- OLED_Refresh();
-
- }
-
- OLED_Clear();
-
- OLED_ShowString(0,16,(u8*)"24C04 Ready!",16);
-
- OLED_Refresh();
-
- //OLED TEST
-
- OLED_ShowString(0,0,(u8*)"Start Write...",16);
-
- AT24CXX_Write(0,(u8*)TEXT_Buffer,SIZE);
-
- OLED_ShowString(0,16,(u8*)"Write Finished!",16);//提示传送完成
-
- OLED_Refresh();
-
- delay_ms(5000);
-
- OLED_Clear();
-
- OLED_ShowString(0,0,(u8*)"Start Read.... ",16);
-
- AT24CXX_Read(0,datatemp,SIZE);
-
- OLED_ShowString(0,16,(u8*)"ReadeData Is: ",16);//提示传送完成
-
- OLED_ShowString(16,32,(u8*)datatemp,16);//显示读到的字符串
-
- OLED_Refresh();
-
- delay_ms(500);
-
-
-
- //FLASH
-
- W25QXX_Init(); //W25QXX初始化
-
- OLED_Clear();
-
- while(W25QXX_ReadID()!=B25Q16) //检测不到B25Q16
-
- {
-
- OLED_ShowString(0,0,(u8*)"Check Failed!",16);
-
- delay_ms(500);
-
- OLED_ShowString(0,16,(u8*)"Please Check!",16);
-
- delay_ms(500);
-
- printf("read id : 0x%x\r\n",W25QXX_ReadID());
-
- OLED_Refresh();
-
- LED0=!LED0;//DS0闪烁
-
- }
-
- //printf("read id : 0x%x\r\n",W25QXX_ReadID());
-
- OLED_ShowString(0,32,(u8*)"W25Q64 Ready!",16);
-
- OLED_Refresh();
-
- FLASH_SIZE=2*1024*1024; //FLASH 大小为2M字节
-
- //W25Q64 TEST
-
- OLED_Clear();
-
- OLED_ShowString(0,0,(u8*)"Start Write...",16);
-
- W25QXX_Write((u8*)TEXT_Buffer2,FLASH_SIZE-100,SIZE2); //从倒数第100个地址处开始,写入SIZE长度的数据
-
- OLED_ShowString(0,16,(u8*)"Write Finished!",16);//提示传送完成
-
- OLED_Refresh();
-
- delay_ms(5000);
-
- OLED_Clear();
-
- OLED_ShowString(0,0,(u8*)"Start Read.... ",16);
-
- W25QXX_Read(datatemp2,FLASH_SIZE-100,SIZE2); //从倒数第100个地址处开始,读出SIZE个字节
-
- OLED_ShowString(0,16,(u8*)"ReadeData Is: ",16);//提示传送完成
-
- OLED_ShowString(16,32,(u8*)datatemp2,16);//显示读到的字符串
-
- OLED_Refresh();
-
- delay_ms(500);
-
- //SD TEST
-
- OLED_Clear();
-
- while(SD_Initialize())//检测不到SD卡
-
- {
-
- OLED_ShowString(0,0,(u8*)"SD Card Error!",16);
-
- OLED_Refresh();
-
- delay_ms(500);
-
- OLED_ShowString(0,16,(u8*)"Please Check! ",16);
-
- OLED_Refresh();
-
- delay_ms(500);
-
- LED0=!LED0;//DS0闪烁
-
- }
-
- //检测SD卡成功
-
- OLED_Clear();
-
- OLED_ShowString(0,16,(u8*)"SD Card OK ",16);
-
- OLED_ShowString(0,32,(u8*)"Size: MB",16);
-
- sd_size=SD_GetSectorCount();//得到扇区数
-
- OLED_ShowNum(8*6,32,sd_size>>11,5,16);//显示SD卡容量
- OLED_Refresh();

好了,就到这,谢谢大家观看~。
---------------------
作者:qjp1988113
链接:https://bbs.21ic.com/icview-3147192-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。