本帖最后由 qjp1988113 于 2021-7-12 21:19 编辑
#申请原创# 最近要调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。
支持包请到https://github.com/rogerclarkmelbourne上下载,该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();
具体代码如下:
RBT6_DEMO_BASE - Send.rar
(1017.46 KB, 下载次数: 17)
实物现象:
PDF原理图:
Schematic_STM32F103RX_ARDUINO_DEMO copy_2021-07-12.pdf
(180.65 KB, 下载次数: 21)
转换的XD格式工程:
Project_STM32F103RX_ARDUINO_DEMO copy(AD).rar
(530.9 KB, 下载次数: 16)
LCEDA格式工程:
Project_STM32F103RX_ARDUINO_DEMO copy(LCEDA).zip
(462.95 KB, 下载次数: 17)
好了,就到这,谢谢大家观看~
|