当前位置:   article > 正文

[STM32F1]我做了个STM32F103的ARDUINO接口的板子_stm32f103+arduino tinyusb

stm32f103+arduino tinyusb

最近要调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对应的。 

  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个 B25Q16SD
  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. //返回值:0NO_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. //返回值:0NO_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
链接:https://bbs.21ic.com/icview-3147192-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/717223
推荐阅读
相关标签
  

闽ICP备14008679号