你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验之谈】基于STM32F103的ARDUINO接口的板子的经验分享

[复制链接]
STMCU小助手 发布时间:2022-12-10 23:00

最近要调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。
由于时间有限,这里本人并未具体尝试。
这里当做普通开发板使用,并调试了部分外设程序.
这里,如果之前写过W25Q16驱动的,对于BY25Q16而言,寄存器指令几乎一致,唯一不同的时ID:

具体指令表格:

我们把本例程中用到的对应ID,换成BY25Q16对应的。

  1. //定义B25Q16 ID 由规格书所得

  2. #<font color="#ff0000"><b>define B25Q16         0X6814</b></font>



  3. extern u16 W25QXX_TYPE;                                        //



  4. #define        W25QXX_CS                 PAout(8)                  //

  5.                                  



  6. //BY25Q16对于寄存器一致

  7. #define W25X_WriteEnable                0x06

  8. #define W25X_WriteDisable                0x04

  9. #define W25X_ReadStatusReg                0x05

  10. #define W25X_WriteStatusReg                0x01

  11. #define W25X_ReadData                        0x03

  12. #define W25X_FastReadData                0x0B

  13. #define W25X_FastReadDual                0x3B

  14. #define W25X_PageProgram                0x02

  15. #define W25X_BlockErase                        0xD8

  16. #define W25X_SectorErase                0x20

  17. #define W25X_ChipErase                        0xC7

  18. #define W25X_PowerDown                        0xB9

  19. #define W25X_ReleasePowerDown        0xAB

  20. #define W25X_DeviceID                        0xAB

  21. #define W25X_ManufactDeviceID        0x90

  22. #define W25X_JedecDeviceID                0x9F



  23. void W25QXX_Init(void);

  24. u16  W25QXX_ReadID(void);                              //

  25. u8         W25QXX_ReadSR(void);                        //

  26. void W25QXX_Write_SR(u8 sr);                          //

  27. void W25QXX_Write_Enable(void);                  //

  28. void W25QXX_Write_Disable(void);                //

  29. void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);

  30. void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead);   //

  31. void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);//

  32. void W25QXX_Erase_Chip(void);                      //

  33. void W25QXX_Erase_Sector(u32 Dst_Addr);        //

  34. void W25QXX_Wait_Busy(void);                   //

  35. void W25QXX_PowerDown(void);                //

  36. void W25QXX_WAKEUP(void);                                //
复制代码



至于BL24C02则几乎完全一致,AT24C02的代码都无需修改:
具体地址定义及读写时序:

<blockquote>#include "24cxx.h"

着重说明,这里的SD卡用的是SPI模式,而不是SDIO模式:


本板中BY25Q16与SD共用SPI1,通过CS端切换使用:

  1. #include "sys.h"

  2. #include "mmc_sd.h"                           

  3. #include "spi.h"

  4. #include "usart.h"        

  5.                                    

  6. u8  SD_Type=0;//SD卡的类型

  7. 移植修改区///

  8. //移植时候的接口

  9. //data:要写入的数据

  10. //返回值:读到的数据

  11. u8 SD_SPI_ReadWriteByte(u8 data)

  12. {

  13.         return SPI2_ReadWriteByte(data);

  14. }         

  15. //SD卡初始化的时候,需要低速

  16. void SD_SPI_SpeedLow(void)

  17. {

  18.          SPI2_SetSpeed(SPI_BaudRatePrescaler_256);//设置到低速模式        

  19. }

  20. //SD卡正常工作的时候,可以高速了

  21. void SD_SPI_SpeedHigh(void)

  22. {

  23.          SPI2_SetSpeed(SPI_BaudRatePrescaler_2);//设置到高速模式        

  24. }

  25. //SPI硬件层初始化

  26. //FLASH_CS-->PA8

  27. //SD_CS-->PD2

  28. void SD_SPI_Init(void)

  29. {

  30.     //设置硬件上与SD卡相关联的控制引脚输出

  31.     //禁止其他外设(NRF/W25Q64)对SD卡产生影响

  32.     //目前仅关在2个 B25Q16 及SD卡



  33.     GPIO_InitTypeDef GPIO_InitStructure;

  34.     RCC_APB2PeriphClockCmd(        RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE );//PORTB时钟使能



  35.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;  // PA8 推挽

  36.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //推挽输出

  37.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  38.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  39.     GPIO_SetBits(GPIOA,GPIO_Pin_8);



  40.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;  // PD2 推挽

  41.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //推挽输出

  42.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  43.     GPIO_Init(GPIOD, &GPIO_InitStructure);

  44.     GPIO_SetBits(GPIOD,GPIO_Pin_2);



  45.     SPI2_Init();

  46.     SD_CS=1;

  47. }

  48. ///

  49. //取消选择,释放SPI总线

  50. void SD_DisSelect(void)

  51. {

  52.         SD_CS=1;

  53.          SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟

  54. }

  55. //选择sd卡,并且等待卡准备OK

  56. //返回值:0,成功;1,失败;

  57. u8 SD_Select(void)

  58. {

  59.         SD_CS=0;

  60.         if(SD_WaitReady()==0)return 0;//等待成功

  61.         SD_DisSelect();

  62.         return 1;//等待失败

  63. }

  64. //等待卡准备好

  65. //返回值:0,准备好了;其他,错误代码

  66. u8 SD_WaitReady(void)

  67. {

  68.         u32 t=0;

  69.         do

  70.         {

  71.                 if(SD_SPI_ReadWriteByte(0XFF)==0XFF)return 0;//OK

  72.                 t++;                          

  73.         }while(t<0XFFFFFF);//等待

  74.         return 1;

  75. }

  76. //等待SD卡回应

  77. //Response:要得到的回应值

  78. //返回值:0,成功得到了该回应值

  79. //    其他,得到回应值失败

  80. u8 SD_GetResponse(u8 Response)

  81. {

  82.         u16 Count=0xFFFF;//等待次数                                                            

  83.         while ((SD_SPI_ReadWriteByte(0XFF)!=Response)&&Count)Count--;//等待得到准确的回应            

  84.         if (Count==0)return MSD_RESPONSE_FAILURE;//得到回应失败   

  85.         else return MSD_RESPONSE_NO_ERROR;//正确回应

  86. }

  87. //从sd卡读取一个数据包的内容

  88. //buf:数据缓存区

  89. //len:要读取的数据长度.

  90. //返回值:0,成功;其他,失败;        

  91. u8 SD_RecvData(u8*buf,u16 len)

  92. {                                    

  93.         if(SD_GetResponse(0xFE))return 1;//等待SD卡发回数据起始令牌0xFE

  94.     while(len--)//开始接收数据

  95.     {

  96.         *buf=SPI2_ReadWriteByte(0xFF);

  97.         buf++;

  98.     }

  99.     //下面是2个伪CRC(dummy CRC)

  100.     SD_SPI_ReadWriteByte(0xFF);

  101.     SD_SPI_ReadWriteByte(0xFF);                                                                                                                     

  102.     return 0;//读取成功

  103. }

  104. //向sd卡写入一个数据包的内容 512字节

  105. //buf:数据缓存区

  106. //cmd:指令

  107. //返回值:0,成功;其他,失败;        

  108. u8 SD_SendBlock(u8*buf,u8 cmd)

  109. {        

  110.         u16 t;                           

  111.         if(SD_WaitReady())return 1;//等待准备失效

  112.         SD_SPI_ReadWriteByte(cmd);

  113.         if(cmd!=0XFD)//不是结束指令

  114.         {

  115.                 for(t=0;t<512;t++)SPI2_ReadWriteByte(buf[t]);//提高速度,减少函数传参时间

  116.             SD_SPI_ReadWriteByte(0xFF);//忽略crc

  117.             SD_SPI_ReadWriteByte(0xFF);

  118.                 t=SD_SPI_ReadWriteByte(0xFF);//接收响应

  119.                 if((t&0x1F)!=0x05)return 2;//响应错误                                                                                                                     

  120.         }                                                                                                                                                                       

  121.     return 0;//写入成功

  122. }



  123. //向SD卡发送一个命令

  124. //输入: u8 cmd   命令

  125. //      u32 arg  命令参数

  126. //      u8 crc   crc校验值           

  127. //返回值:SD卡返回的响应                                                                                                                          

  128. u8 SD_SendCmd(u8 cmd, u32 arg, u8 crc)

  129. {

  130.     u8 r1;        

  131.         u8 Retry=0;

  132.         SD_DisSelect();//取消上次片选

  133.         if(SD_Select())return 0XFF;//片选失效

  134.         //发送

  135.     SD_SPI_ReadWriteByte(cmd | 0x40);//分别写入命令

  136.     SD_SPI_ReadWriteByte(arg >> 24);

  137.     SD_SPI_ReadWriteByte(arg >> 16);

  138.     SD_SPI_ReadWriteByte(arg >> 8);

  139.     SD_SPI_ReadWriteByte(arg);         

  140.     SD_SPI_ReadWriteByte(crc);

  141.         if(cmd==CMD12)SD_SPI_ReadWriteByte(0xff);//Skip a stuff byte when stop reading

  142.     //等待响应,或超时退出

  143.         Retry=0X1F;

  144.         do

  145.         {

  146.                 r1=SD_SPI_ReadWriteByte(0xFF);

  147.         }while((r1&0X80) && Retry--);         

  148.         //返回状态值

  149.     return r1;

  150. }                                                                                                                                                                              

  151. //获取SD卡的CID信息,包括制造商信息

  152. //输入: u8 *cid_data(存放CID的内存,至少16Byte)         

  153. //返回值:0:NO_ERR

  154. //                 1:错误                                                                                                                  

  155. u8 SD_GetCID(u8 *cid_data)

  156. {

  157.     u8 r1;           

  158.     //发CMD10命令,读CID

  159.     r1=SD_SendCmd(CMD10,0,0x01);

  160.     if(r1==0x00)

  161.         {

  162.                 r1=SD_RecvData(cid_data,16);//接收16个字节的数据         

  163.     }

  164.         SD_DisSelect();//取消片选

  165.         if(r1)return 1;

  166.         else return 0;

  167. }                                                                                                                                                                  

  168. //获取SD卡的CSD信息,包括容量和速度信息

  169. //输入:u8 *cid_data(存放CID的内存,至少16Byte)            

  170. //返回值:0:NO_ERR

  171. //                 1:错误                                                                                                                  

  172. u8 SD_GetCSD(u8 *csd_data)

  173. {

  174.     u8 r1;         

  175.     r1=SD_SendCmd(CMD9,0,0x01);//发CMD9命令,读CSD

  176.     if(r1==0)

  177.         {

  178.             r1=SD_RecvData(csd_data, 16);//接收16个字节的数据

  179.     }

  180.         SD_DisSelect();//取消片选

  181.         if(r1)return 1;

  182.         else return 0;

  183. }  

  184. //获取SD卡的总扇区数(扇区数)   

  185. //返回值:0: 取容量出错

  186. //       其他:SD卡的容量(扇区数/512字节)

  187. //每扇区的字节数必为512,因为如果不是512,则初始化不能通过.                                                                                                                  

  188. u32 SD_GetSectorCount(void)

  189. {

  190.     u8 csd[16];

  191.     u32 Capacity;  

  192.     u8 n;

  193.         u16 csize;                                             

  194.         //取CSD信息,如果期间出错,返回0

  195.     if(SD_GetCSD(csd)!=0) return 0;            

  196.     //如果为SDHC卡,按照下面方式计算

  197.     if((csd[0]&0xC0)==0x40)         //V2.00的卡

  198.     {        

  199.                 csize = csd[9] + ((u16)csd[8] << 8) + 1;

  200.                 Capacity = (u32)csize << 10;//得到扇区数                           

  201.     }else//V1.XX的卡

  202.     {        

  203.                 n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;

  204.                 csize = (csd[8] >> 6) + ((u16)csd[7] << 2) + ((u16)(csd[6] & 3) << 10) + 1;

  205.                 Capacity= (u32)csize << (n - 9);//得到扇区数   

  206.     }

  207.     return Capacity;

  208. }

  209. //初始化SD卡

  210. u8 SD_Initialize(void)

  211. {

  212.     u8 r1;      // 存放SD卡的返回值

  213.     u16 retry;  // 用来进行超时计数

  214.     u8 buf[4];  

  215.         u16 i;



  216.         SD_SPI_Init();                //初始化IO

  217.          SD_SPI_SpeedLow();        //设置到低速模式

  218.          for(i=0;i<10;i++)SD_SPI_ReadWriteByte(0XFF);//发送最少74个脉冲

  219.         retry=20;

  220.         do

  221.         {

  222.                 r1=SD_SendCmd(CMD0,0,0x95);//进入IDLE状态

  223.         }while((r1!=0X01) && retry--);

  224.          SD_Type=0;//默认无卡

  225.         if(r1==0X01)

  226.         {

  227.                 if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0

  228.                 {

  229.                         for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);        //Get trailing return value of R7 resp

  230.                         if(buf[2]==0X01&&buf[3]==0XAA)//卡是否支持2.7~3.6V

  231.                         {

  232.                                 retry=0XFFFE;

  233.                                 do

  234.                                 {

  235.                                         SD_SendCmd(CMD55,0,0X01);        //发送CMD55

  236.                                         r1=SD_SendCmd(CMD41,0x40000000,0X01);//发送CMD41

  237.                                 }while(r1&&retry--);

  238.                                 if(retry&&SD_SendCmd(CMD58,0,0X01)==0)//鉴别SD2.0卡版本开始

  239.                                 {

  240.                                         for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);//得到OCR值

  241.                                         if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC;    //检查CCS

  242.                                         else SD_Type=SD_TYPE_V2;   

  243.                                 }

  244.                         }

  245.                 }else//SD V1.x/ MMC        V3

  246.                 {

  247.                         SD_SendCmd(CMD55,0,0X01);                //发送CMD55

  248.                         r1=SD_SendCmd(CMD41,0,0X01);        //发送CMD41

  249.                         if(r1<=1)

  250.                         {               

  251.                                 SD_Type=SD_TYPE_V1;

  252.                                 retry=0XFFFE;

  253.                                 do //等待退出IDLE模式

  254.                                 {

  255.                                         SD_SendCmd(CMD55,0,0X01);        //发送CMD55

  256.                                         r1=SD_SendCmd(CMD41,0,0X01);//发送CMD41

  257.                                 }while(r1&&retry--);

  258.                         }else//MMC卡不支持CMD55+CMD41识别

  259.                         {

  260.                                 SD_Type=SD_TYPE_MMC;//MMC V3

  261.                                 retry=0XFFFE;

  262.                                 do //等待退出IDLE模式

  263.                                 {                                                                                            

  264.                                         r1=SD_SendCmd(CMD1,0,0X01);//发送CMD1

  265.                                 }while(r1&&retry--);  

  266.                         }

  267.                         if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)SD_Type=SD_TYPE_ERR;//错误的卡

  268.                 }

  269.         }

  270.         SD_DisSelect();//取消片选

  271.         SD_SPI_SpeedHigh();//高速

  272.         if(SD_Type)return 0;

  273.         else if(r1)return r1;            

  274.         return 0xaa;//其他错误

  275. }

  276. //读SD卡

  277. //buf:数据缓存区

  278. //sector:扇区

  279. //cnt:扇区数

  280. //返回值:0,ok;其他,失败.

  281. u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt)

  282. {

  283.         u8 r1;

  284.         if(SD_Type!=SD_TYPE_V2HC)sector <<= 9;//转换为字节地址

  285.         if(cnt==1)

  286.         {

  287.                 r1=SD_SendCmd(CMD17,sector,0X01);//读命令

  288.                 if(r1==0)//指令发送成功

  289.                 {

  290.                         r1=SD_RecvData(buf,512);//接收512个字节           

  291.                 }

  292.         }else

  293.         {

  294.                 r1=SD_SendCmd(CMD18,sector,0X01);//连续读命令

  295.                 do

  296.                 {

  297.                         r1=SD_RecvData(buf,512);//接收512个字节         

  298.                         buf+=512;  

  299.                 }while(--cnt && r1==0);         

  300.                 SD_SendCmd(CMD12,0,0X01);        //发送停止命令

  301.         }   

  302.         SD_DisSelect();//取消片选

  303.         return r1;//

  304. }

  305. //写SD卡

  306. //buf:数据缓存区

  307. //sector:起始扇区

  308. //cnt:扇区数

  309. //返回值:0,ok;其他,失败.

  310. u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt)

  311. {

  312.         u8 r1;

  313.         if(SD_Type!=SD_TYPE_V2HC)sector *= 512;//转换为字节地址

  314.         if(cnt==1)

  315.         {

  316.                 r1=SD_SendCmd(CMD24,sector,0X01);//读命令

  317.                 if(r1==0)//指令发送成功

  318.                 {

  319.                         r1=SD_SendBlock(buf,0xFE);//写512个字节           

  320.                 }

  321.         }else

  322.         {

  323.                 if(SD_Type!=SD_TYPE_MMC)

  324.                 {

  325.                         SD_SendCmd(CMD55,0,0X01);        

  326.                         SD_SendCmd(CMD23,cnt,0X01);//发送指令        

  327.                 }

  328.                  r1=SD_SendCmd(CMD25,sector,0X01);//连续读命令

  329.                 if(r1==0)

  330.                 {

  331.                         do

  332.                         {

  333.                                 r1=SD_SendBlock(buf,0xFC);//接收512个字节         

  334.                                 buf+=512;  

  335.                         }while(--cnt && r1==0);

  336.                         r1=SD_SendBlock(0,0xFD);//接收512个字节

  337.                 }

  338.         }   

  339.         SD_DisSelect();//取消片选

  340.         return r1;//

  341. }        



  342. //SD test

  343. //#include "malloc.h"



  344. //读取SD卡的指定扇区的内容,并通过串口1输出

  345. sec:扇区物理地址编号

  346. //void SD_Read_Sectorx(u32 sec)

  347. //{

  348. //        u8 *buf;

  349. //        u16 i;

  350. //        buf=mymalloc(512);                                //申请内存

  351. //        if(SD_ReadDisk(buf,sec,1)==0)        //读取0扇区的内容

  352. //        {        

  353. //                LCD_ShowString(60,190,200,16,16,"USART1 Sending Data...");

  354. //                printf("SECTOR 0 DATA:\r\n");

  355. //                for(i=0;i<512;i++)printf("%x ",buf[i]);//打印sec扇区数据               

  356. //                printf("\r\nDATA ENDED\r\n");

  357. //                LCD_ShowString(60,190,200,16,16,"USART1 Send Data Over!");

  358. //        }

  359. //        myfree(buf);//释放内存        

  360. //}

复制代码


另MCU中的硬件IIC引脚均接了上拉,以防外接模块没有加。
对于OLED12864,就没什么好说的了,直接模拟IIC驱动:

  1. #include "oled.h"

  2. #include "stdlib.h"

  3. #include "oledfont.h"           

  4. #include "delay.h"



  5. u8 OLED_GRAM[144][8];







  6. 具体IIC控制函数

  7. //起始信号

  8. static void I2C_Start(void)

  9. {

  10.         OLED_SDIN_Set();

  11.         OLED_SCLK_Set();

  12.         OLED_SDIN_Clr();

  13.         OLED_SCLK_Clr();

  14. }



  15. //结束信号

  16. static void I2C_Stop(void)

  17. {

  18.         OLED_SCLK_Set();

  19.         OLED_SDIN_Clr();

  20.         OLED_SDIN_Set();

  21. }



  22. //等待信号响应

  23. static void I2C_WaitAck(void) //测数据信号的电平

  24. {

  25.         OLED_SCLK_Set();

  26.         OLED_SCLK_Clr();

  27. }



  28. //写入一个字节

  29. static void Send_Byte(u8 dat)

  30. {

  31.         u8 i;

  32.         for(i=0;i<8;i++)

  33.         {

  34.                 OLED_SCLK_Clr();//将时钟信号设置为低电平

  35.                 if(dat&0x80)//将dat的8位从最高位依次写入

  36.                 {

  37.                         OLED_SDIN_Set();

  38.     }

  39.                 else

  40.                 {

  41.                         OLED_SDIN_Clr();

  42.     }

  43.                 OLED_SCLK_Set();//将时钟信号设置为高电平

  44.                 OLED_SCLK_Clr();//将时钟信号设置为低电平

  45.                 dat<<=1;

  46.   }

  47. }



  48. //发送一个字节

  49. //向SSD1306写入一个字节。

  50. //mode:数据/命令标志 0,表示命令;1,表示数据;

  51. void OLED_WR_Byte(u8 dat,u8 mode)

  52. {

  53.         I2C_Start();

  54.         Send_Byte(0x78);

  55.         I2C_WaitAck();

  56.         if(mode){Send_Byte(0x40);}

  57.   else{Send_Byte(0x00);}

  58.         I2C_WaitAck();

  59.         Send_Byte(dat);

  60.         I2C_WaitAck();

  61.         I2C_Stop();

  62. }





  63. //反显函数

  64. void OLED_ColorTurn(u8 i)

  65. {

  66.         if(i==0)

  67.                 {

  68.                         OLED_WR_Byte(0xA6,OLED_CMD);//正常显示

  69.                 }

  70.         if(i==1)

  71.                 {

  72.                         OLED_WR_Byte(0xA7,OLED_CMD);//反色显示

  73.                 }

  74. }



  75. //屏幕旋转180度

  76. void OLED_DisplayTurn(u8 i)

  77. {

  78.         if(i==0)

  79.                 {

  80.                         OLED_WR_Byte(0xC8,OLED_CMD);//正常显示

  81.                         OLED_WR_Byte(0xA1,OLED_CMD);

  82.                 }

  83.         if(i==1)

  84.                 {

  85.                         OLED_WR_Byte(0xC0,OLED_CMD);//反转显示

  86.                         OLED_WR_Byte(0xA0,OLED_CMD);

  87.                 }

  88. }





  89. //开启OLED显示

  90. void OLED_DisPlay_On(void)

  91. {

  92.         OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能

  93.         OLED_WR_Byte(0x14,OLED_CMD);//开启电荷泵

  94.         OLED_WR_Byte(0xAF,OLED_CMD);//点亮屏幕

  95. }



  96. //关闭OLED显示

  97. void OLED_DisPlay_Off(void)

  98. {

  99.         OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能

  100.         OLED_WR_Byte(0x10,OLED_CMD);//关闭电荷泵

  101.         OLED_WR_Byte(0xAF,OLED_CMD);//关闭屏幕

  102. }



  103. //更新显存到OLED        

  104. void OLED_Refresh(void)

  105. {

  106.         u8 i,n;

  107.         for(i=0;i<8;i++)

  108.         {

  109.            OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址

  110.            OLED_WR_Byte(0x00,OLED_CMD);   //设置低列起始地址

  111.            OLED_WR_Byte(0x10,OLED_CMD);   //设置高列起始地址

  112.            for(n=0;n<128;n++)

  113.                  OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA);

  114.   }

  115. }

  116. //自定义清屏函数

  117. void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2)

  118. {

  119.         u8 i,n;

  120.         for(i=y1;i<y2;i++)

  121.         {

  122.            for(n=x1;n<x2;n++)

  123.                         {

  124.                          OLED_GRAM[n][i]=0;//清除所有数据

  125.                         }

  126.   }

  127.         OLED_Refresh();//更新显示

  128. }

  129. //清屏函数

  130. void OLED_Clear(void)

  131. {

  132.         u8 i,n;

  133.         for(i=0;i<8;i++)

  134.         {

  135.            for(n=0;n<128;n++)

  136.                         {

  137.                          OLED_GRAM[n][i]=0;//清除所有数据

  138.                         }

  139.   }

  140.         OLED_Refresh();//更新显示

  141. }



  142. //画点

  143. //x:0~127

  144. //y:0~63

  145. void OLED_DrawPoint(u8 x,u8 y)

  146. {

  147.         u8 i,m,n;

  148.         i=y/8;

  149.         m=y%8;

  150.         n=1<<m;

  151.         OLED_GRAM[x][i]|=n;

  152. }



  153. //清除一个点

  154. //x:0~127

  155. //y:0~63

  156. void OLED_ClearPoint(u8 x,u8 y)

  157. {

  158.         u8 i,m,n;

  159.         i=y/8;

  160.         m=y%8;

  161.         n=1<<m;

  162.         OLED_GRAM[x][i]=~OLED_GRAM[x][i];

  163.         OLED_GRAM[x][i]|=n;

  164.         OLED_GRAM[x][i]=~OLED_GRAM[x][i];

  165. }





  166. //画线

  167. //x:0~128

  168. //y:0~64

  169. void OLED_DrawLine(u8 x1,u8 y1,u8 x2,u8 y2)

  170. {

  171.         u8 i,k,k1,k2;

  172.         if((1)||(x2>128)||(1)||(y2>64)||(x1>x2)||(y1>y2))return;

  173.         if(x1==x2)    //画竖线

  174.         {

  175.                         for(i=0;i<(y2-y1);i++)

  176.                         {

  177.                                 OLED_DrawPoint(x1,y1+i);

  178.                         }

  179.   }

  180.         else if(y1==y2)   //画横线

  181.         {

  182.                         for(i=0;i<(x2-x1);i++)

  183.                         {

  184.                                 OLED_DrawPoint(x1+i,y1);

  185.                         }

  186.   }

  187.         else      //画斜线

  188.         {

  189.                 k1=y2-y1;

  190.                 k2=x2-x1;

  191.                 k=k1*10/k2;

  192.                 for(i=0;i<(x2-x1);i++)

  193.                         {

  194.                           OLED_DrawPoint(x1+i,y1+i*k/10);

  195.                         }

  196.         }

  197. }

  198. //x,y:圆心坐标

  199. //r:圆的半径

  200. void OLED_DrawCircle(u8 x,u8 y,u8 r)

  201. {

  202.         int a, b,num;

  203.     a = 0;

  204.     b = r;

  205.     while(2 * b * b >= r * r)      

  206.     {

  207.         OLED_DrawPoint(x + a, y - b);

  208.         OLED_DrawPoint(x - a, y - b);

  209.         OLED_DrawPoint(x - a, y + b);

  210.         OLED_DrawPoint(x + a, y + b);



  211.         OLED_DrawPoint(x + b, y + a);

  212.         OLED_DrawPoint(x + b, y - a);

  213.         OLED_DrawPoint(x - b, y - a);

  214.         OLED_DrawPoint(x - b, y + a);

  215.         

  216.         a++;

  217.         num = (a * a + b * b) - r*r;//计算画的点离圆心的距离

  218.         if(num > 0)

  219.         {

  220.             b--;

  221.             a--;

  222.         }

  223.     }

  224. }







  225. //在指定位置显示一个字符,包括部分字符

  226. //x:0~127

  227. //y:0~63

  228. //size:选择字体 12/16/24

  229. void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size1)

  230. {

  231.         u8 i,m,temp,size2,chr1;

  232.         u8 y0=y;

  233.         size2=(size1/8+((size1%8)?1:0))*(size1/2);  //得到字体一个字符对应点阵集所占的字节数

  234.         chr1=chr-' ';  //计算偏移后的值

  235.         for(i=0;i<size2;i++)

  236.         {

  237.                 if(size1==12)

  238.         {temp=asc2_1206[chr1][i];} //调用1206字体

  239.                 else if(size1==16)

  240.         {temp=asc2_1608[chr1][i];} //调用1608字体

  241.                 else if(size1==24)

  242.         {temp=asc2_2412[chr1][i];} //调用2412字体

  243.                 else return;

  244.                                 for(m=0;m<8;m++)           //写入数据

  245.                                 {

  246.                                         if(temp&0x80)OLED_DrawPoint(x,y);

  247.                                         else OLED_ClearPoint(x,y);

  248.                                         temp<<=1;

  249.                                         y++;

  250.                                         if((y-y0)==size1)

  251.                                         {

  252.                                                 y=y0;

  253.                                                 x++;

  254.                                                 break;

  255.           }

  256.                                 }

  257.   }

  258. }





  259. //显示字符串

  260. //x,y:起点坐标  

  261. //size1:字体大小

  262. //*chr:字符串起始地址

  263. void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 size1)

  264. {

  265.         while((*chr>=' ')&&(*chr<='~'))//判断是不是非法字符!

  266.         {

  267.                 OLED_ShowChar(x,y,*chr,size1);

  268.                 x+=size1/2;

  269.                 if(x>128-size1)  //换行

  270.                 {

  271.                         x=0;

  272.                         y+=2;

  273.     }

  274.                 chr++;

  275.   }

  276. }



  277. //m^n

  278. u32 OLED_Pow(u8 m,u8 n)

  279. {

  280.         u32 result=1;

  281.         while(n--)

  282.         {

  283.           result*=m;

  284.         }

  285.         return result;

  286. }



  287. 显示2个数字

  288. x,y :起点坐标         

  289. len :数字的位数

  290. size:字体大小

  291. void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size1)

  292. {

  293.         u8 t,temp;

  294.         for(t=0;t<len;t++)

  295.         {

  296.                 temp=(num/OLED_Pow(10,len-t-1))%10;

  297.                         if(temp==0)

  298.                         {

  299.                                 OLED_ShowChar(x+(size1/2)*t,y,'0',size1);

  300.       }

  301.                         else

  302.                         {

  303.                           OLED_ShowChar(x+(size1/2)*t,y,temp+'0',size1);

  304.                         }

  305.   }

  306. }



  307. //显示汉字

  308. //x,y:起点坐标

  309. //num:汉字对应的序号

  310. void OLED_ShowChinese(u8 x,u8 y,u8 num,u8 size1)

  311. {

  312.         u8 i,m,n=0,temp,chr1;

  313.         u8 x0=x,y0=y;

  314.         u8 size3=size1/8;

  315.         while(size3--)

  316.         {

  317.                 chr1=num*size1/8+n;

  318.                 n++;

  319.                         for(i=0;i<size1;i++)

  320.                         {

  321.                                 if(size1==16)

  322.                                                 {temp=Hzk1[chr1][i];}//调用16*16字体

  323.                                 else if(size1==24)

  324.                                                 {temp=Hzk2[chr1][i];}//调用24*24字体

  325.                                 else if(size1==32)      

  326.                                                 {temp=Hzk3[chr1][i];}//调用32*32字体

  327.                                 else if(size1==64)

  328.                                                 {temp=Hzk4[chr1][i];}//调用64*64字体

  329.                                 else return;

  330.                                                         

  331.                                                 for(m=0;m<8;m++)

  332.                                                         {

  333.                                                                 if(temp&0x01)OLED_DrawPoint(x,y);

  334.                                                                 else OLED_ClearPoint(x,y);

  335.                                                                 temp>>=1;

  336.                                                                 y++;

  337.                                                         }

  338.                                                         x++;

  339.                                                         if((x-x0)==size1)

  340.                                                         {x=x0;y0=y0+8;}

  341.                                                         y=y0;

  342.                          }

  343.         }

  344. }



  345. //num 显示汉字的个数

  346. //space 每一遍显示的间隔

  347. void OLED_ScrollDisplay(u8 num,u8 space)

  348. {

  349.         u8 i,n,t=0,m=0,r;

  350.         while(1)

  351.         {

  352.                 if(m==0)

  353.                 {

  354.             OLED_ShowChinese(128,24,t,16); //写入一个汉字保存在OLED_GRAM[][]数组中

  355.                         t++;

  356.                 }

  357.                 if(t==num)

  358.                         {

  359.                                 for(r=0;r<16*space;r++)      //显示间隔

  360.                                  {

  361.                                         for(i=0;i<144;i++)

  362.                                                 {

  363.                                                         for(n=0;n<8;n++)

  364.                                                         {

  365.                                                                 OLED_GRAM[i-1][n]=OLED_GRAM[i][n];

  366.                                                         }

  367.                                                 }

  368.            OLED_Refresh();

  369.                                  }

  370.         t=0;

  371.       }

  372.                 m++;

  373.                 if(m==16){m=0;}

  374.                 for(i=0;i<144;i++)   //实现左移

  375.                 {

  376.                         for(n=0;n<8;n++)

  377.                         {

  378.                                 OLED_GRAM[i-1][n]=OLED_GRAM[i][n];

  379.                         }

  380.                 }

  381.                 OLED_Refresh();

  382.         }

  383. }



  384. //配置写入数据的起始位置

  385. void OLED_WR_BP(u8 x,u8 y)

  386. {

  387.         OLED_WR_Byte(0xb0+y,OLED_CMD);//设置行起始地址

  388.         OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);

  389.         OLED_WR_Byte((x&0x0f)|0x01,OLED_CMD);

  390. }



  391. //x0,y0:起点坐标

  392. //x1,y1:终点坐标

  393. //BMP[]:要写入的图片数组

  394. void OLED_ShowPicture(u8 x0,u8 y0,u8 x1,u8 y1,u8 BMP[])

  395. {

  396.         u32 j=0;

  397.         u8 x=0,y=0;

  398.         if(y%8==0)y=0;

  399.         else y+=1;

  400.         for(y=y0;y<y1;y++)

  401.          {

  402.                  OLED_WR_BP(x0,y);

  403.                  for(x=x0;x<x1;x++)

  404.                  {

  405.                          OLED_WR_Byte(BMP[j],OLED_DATA);

  406.                          j++;

  407.      }

  408.          }

  409. }

  410. //OLED的初始化

  411. void OLED_Init(void)

  412. {

  413.         GPIO_InitTypeDef  GPIO_InitStructure;

  414.          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);         //使能C端口时钟

  415.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5;         

  416.          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //推挽输出

  417.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz

  418.          GPIO_Init(GPIOC, &GPIO_InitStructure);          //初始化GPIOC4,5

  419.          GPIO_SetBits(GPIOC,GPIO_Pin_4|GPIO_Pin_5);        

  420.         

  421.         delay_ms(200);

  422.         

  423.         OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel

  424.         OLED_WR_Byte(0x00,OLED_CMD);//---set low column address

  425.         OLED_WR_Byte(0x10,OLED_CMD);//---set high column address

  426.         OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)

  427.         OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register

  428.         OLED_WR_Byte(0xCF,OLED_CMD);// Set SEG Output Current Brightness

  429.         OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常

  430.         OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常

  431.         OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display

  432.         OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)

  433.         OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty

  434.         OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset        Shift Mapping RAM Counter (0x00~0x3F)

  435.         OLED_WR_Byte(0x00,OLED_CMD);//-not offset

  436.         OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency

  437.         OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec

  438.         OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period

  439.         OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock

  440.         OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration

  441.         OLED_WR_Byte(0x12,OLED_CMD);

  442.         OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh

  443.         OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level

  444.         OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)

  445.         OLED_WR_Byte(0x02,OLED_CMD);//

  446.         OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable

  447.         OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable

  448.         OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)

  449.         OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)

  450.         OLED_WR_Byte(0xAF,OLED_CMD);

  451.         OLED_Clear();

  452. }
复制代码



目前仅对几个外设底层驱动进行了编写调试,下面准备上RTT并FATFS。
在main函数中调用:

  1.   //OLED

  2.     OLED_Init();

  3.     OLED_ShowString(40,0,(u8*)"MPU6050",16);

  4.     OLED_Refresh();

  5.     //24CXX

  6.     AT24CXX_Init();                        //IIC初始化

  7.     while(AT24CXX_Check())//检测不到24c02

  8.     {

  9.         OLED_ShowString(0,16,(u8*)"24C04 Check Failed!",16);

  10.         delay_ms(500);

  11.         OLED_ShowString(0,32,(u8*)"Please Check!      ",16);

  12.         delay_ms(500);

  13.         LED0=!LED0;//DS0闪烁

  14.         OLED_Refresh();

  15.     }

  16.     OLED_Clear();

  17.     OLED_ShowString(0,16,(u8*)"24C04 Ready!",16);   

  18.     OLED_Refresh();

  19.     //OLED TEST

  20.     OLED_ShowString(0,0,(u8*)"Start Write...",16);

  21.     AT24CXX_Write(0,(u8*)TEXT_Buffer,SIZE);

  22.     OLED_ShowString(0,16,(u8*)"Write Finished!",16);//提示传送完成

  23.     OLED_Refresh();

  24.     delay_ms(5000);

  25.     OLED_Clear();

  26.     OLED_ShowString(0,0,(u8*)"Start Read.... ",16);

  27.     AT24CXX_Read(0,datatemp,SIZE);

  28.     OLED_ShowString(0,16,(u8*)"ReadeData Is:  ",16);//提示传送完成

  29.     OLED_ShowString(16,32,(u8*)datatemp,16);//显示读到的字符串

  30.     OLED_Refresh();

  31.     delay_ms(500);



  32.     //FLASH

  33.     W25QXX_Init();                        //W25QXX初始化

  34.     OLED_Clear();

  35.     while(W25QXX_ReadID()!=B25Q16)                                                                //检测不到B25Q16

  36.     {

  37.         OLED_ShowString(0,0,(u8*)"Check Failed!",16);

  38.         delay_ms(500);

  39.         OLED_ShowString(0,16,(u8*)"Please Check!",16);

  40.         delay_ms(500);

  41.         printf("read id : 0x%x\r\n",W25QXX_ReadID());

  42.         OLED_Refresh();

  43.         LED0=!LED0;//DS0闪烁

  44.     }

  45.     //printf("read id : 0x%x\r\n",W25QXX_ReadID());

  46.     OLED_ShowString(0,32,(u8*)"W25Q64 Ready!",16);

  47.     OLED_Refresh();  

  48.     FLASH_SIZE=2*1024*1024;        //FLASH 大小为2M字节

  49.     //W25Q64 TEST

  50.     OLED_Clear();

  51.     OLED_ShowString(0,0,(u8*)"Start Write...",16);

  52.     W25QXX_Write((u8*)TEXT_Buffer2,FLASH_SIZE-100,SIZE2);                        //从倒数第100个地址处开始,写入SIZE长度的数据

  53.     OLED_ShowString(0,16,(u8*)"Write Finished!",16);//提示传送完成

  54.     OLED_Refresh();

  55.     delay_ms(5000);

  56.     OLED_Clear();

  57.     OLED_ShowString(0,0,(u8*)"Start Read.... ",16);

  58.     W25QXX_Read(datatemp2,FLASH_SIZE-100,SIZE2);                                        //从倒数第100个地址处开始,读出SIZE个字节

  59.     OLED_ShowString(0,16,(u8*)"ReadeData Is:  ",16);//提示传送完成

  60.     OLED_ShowString(16,32,(u8*)datatemp2,16);//显示读到的字符串

  61.     OLED_Refresh();

  62.     delay_ms(500);

  63.     //SD TEST

  64.     OLED_Clear();

  65.     while(SD_Initialize())//检测不到SD卡

  66.         {

  67.                 OLED_ShowString(0,0,(u8*)"SD Card Error!",16);

  68.         OLED_Refresh();

  69.                 delay_ms(500);                                       

  70.                 OLED_ShowString(0,16,(u8*)"Please Check! ",16);

  71.         OLED_Refresh();

  72.                 delay_ms(500);

  73.                 LED0=!LED0;//DS0闪烁

  74.         }

  75.     //检测SD卡成功

  76.     OLED_Clear();   

  77.     OLED_ShowString(0,16,(u8*)"SD Card OK    ",16);

  78.     OLED_ShowString(0,32,(u8*)"Size:       MB",16);

  79.     sd_size=SD_GetSectorCount();//得到扇区数

  80.     OLED_ShowNum(8*6,32,sd_size>>11,5,16);//显示SD卡容量

  81.     OLED_Refresh();
复制代码


好了,就到这,谢谢大家观看~。
---------------------
作者:qjp1988113


收藏 评论0 发布时间:2022-12-10 23:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版