[STM32F1]我做了个STM32F103的ARDUINO接口的板子

最近要调STM32F1XX,想做个最小系统。手头的ARDUINO接口模块比较大。于是,我做了个STM32F103的ARDUINO接口的板子。
主控用的STM32F103RX(当然也可换成PIN2PIN的国产MCU),W25QXX,24C02,CH340串口,还引出个IIC OLED12864的接口。
用的是LCEDA画的,现在感觉是越来越好用了,我现在几乎放弃XD了。
废话不说,上图:原理图:

 PCB图:


3D视图:

 实物:

其中由于最近国外芯片价格暴涨,板上主要芯片均是国产(最近国产也不便宜了,GD32F103RC要90一片)。
在一家淘宝卖家店,求哥哥拜爷爷,人给了我一片STM32F103RCT6,要了35。这个价格在现在讲很不错了。
其中主要芯片:
STM32F103RCT6------->GD32F103RCT6
W25Q16            ------->BY26Q16
AT24C02           ------->BL24C02
设计时考虑外接的ARDUINO接口。板上已有外设尽量不占用ARDUINO接口。
其中24C02,由于想试验硬件IIC,使用了电阻来选通。具体如图:


如果焊接红框勾选的电阻,则占用PB6/PB7,此时与ARDUINO的IIC接口相连。
如果选用蓝框,则无影响,但这2脚无硬件IIC功能,只能软IIC。
板子设计时,考虑到运行RTT实时操作系统,特地选用大容量的STM32F103RCT6(FLASH:256K,RAM:64K),
而不使用小容量的STM32F103RBT6(FLASH:128K,RAM:20K)),并预留SD卡接口,挂载FATFS功能。
其中W25Q16 2MBYTE的FLASH用来存储字库及对应图片(由于空间2M不是很大,仅准备加载ASCII及宋体16)。
预留IIC接口的OLED,驱动OLED12864,可在上面运行简单的菜单系统或者轻量级的GUI。
板上有USB转串口CH340电路及USB DEVICE电路,可通过跳线帽,强制上拉D+,当然也可以通过引进控制。
设置初期,除了当普通开发板应用外。还兼任考虑ARDUINO,可刷入STM32F103RC ARDUINO底层固件,
并引出ISP下载控制按键。有兴趣的可以刷入ARDUINO固件,在STM32上面体验一把ARDUINO。
支持包请到rogerclarkmelbourne (Roger Clark) · GitHub上下载,该Git仓库中有两个我们需要下载的项目集,
分别是“Arduino_STM32-master”和“STM32duino-bootloader-master”。具体参考本篇**:
https://blog.csdn.net/argon_ghost/article/details/88297262
由于时间有限,这里本人并未具体尝试。
这里当做普通开发板使用,并调试了部分外设程序.
这里,如果之前写过W25Q16驱动的,对于BY25Q16而言,寄存器指令几乎一致,唯一不同的时ID:

具体指令表格:
 

 

 

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

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

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



extern u16 W25QXX_TYPE;                                        //



#define        W25QXX_CS                 PAout(8)                  //

                                 



//BY25Q16对于寄存器一致

#define W25X_WriteEnable                0x06 

#define W25X_WriteDisable                0x04 

#define W25X_ReadStatusReg                0x05 

#define W25X_WriteStatusReg                0x01 

#define W25X_ReadData                        0x03 

#define W25X_FastReadData                0x0B 

#define W25X_FastReadDual                0x3B 

#define W25X_PageProgram                0x02 

#define W25X_BlockErase                        0xD8 

#define W25X_SectorErase                0x20 

#define W25X_ChipErase                        0xC7 

#define W25X_PowerDown                        0xB9 

#define W25X_ReleasePowerDown        0xAB 

#define W25X_DeviceID                        0xAB 

#define W25X_ManufactDeviceID        0x90 

#define W25X_JedecDeviceID                0x9F 



void W25QXX_Init(void);

u16  W25QXX_ReadID(void);                              //

u8         W25QXX_ReadSR(void);                        //

void W25QXX_Write_SR(u8 sr);                          //

void W25QXX_Write_Enable(void);                  //

void W25QXX_Write_Disable(void);                //

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

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

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

void W25QXX_Erase_Chip(void);                      //

void W25QXX_Erase_Sector(u32 Dst_Addr);        //

void W25QXX_Wait_Busy(void);                   //

void W25QXX_PowerDown(void);                //

void W25QXX_WAKEUP(void);                                //

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

<blockquote>#include "24cxx.h" 

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


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

 

#include "sys.h"

#include "mmc_sd.h"                           

#include "spi.h"

#include "usart.h"        

                                   

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

移植修改区///

//移植时候的接口

//data:要写入的数据

//返回值:读到的数据

u8 SD_SPI_ReadWriteByte(u8 data)

{

        return SPI2_ReadWriteByte(data);

}          

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

void SD_SPI_SpeedLow(void)

{

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

}

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

void SD_SPI_SpeedHigh(void)

{

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

}

//SPI硬件层初始化

//FLASH_CS-->PA8

//SD_CS-->PD2

void SD_SPI_Init(void)

{

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

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

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



    GPIO_InitTypeDef GPIO_InitStructure;

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



    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;  // PA8 推挽 

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

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_SetBits(GPIOA,GPIO_Pin_8);



    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;  // PD2 推挽 

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

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOD, &GPIO_InitStructure);

    GPIO_SetBits(GPIOD,GPIO_Pin_2);



    SPI2_Init();

    SD_CS=1;

}

///

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

void SD_DisSelect(void)

{

        SD_CS=1;

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

}

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

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

u8 SD_Select(void)

{

        SD_CS=0;

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

        SD_DisSelect();

        return 1;//等待失败

}

//等待卡准备好

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

u8 SD_WaitReady(void)

{

        u32 t=0;

        do

        {

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

                t++;                          

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

        return 1;

}

//等待SD卡回应

//Response:要得到的回应值

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

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

u8 SD_GetResponse(u8 Response)

{

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

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

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

        else return MSD_RESPONSE_NO_ERROR;//正确回应

}

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

//buf:数据缓存区

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

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

u8 SD_RecvData(u8*buf,u16 len)

{                                    

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

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

    {

        *buf=SPI2_ReadWriteByte(0xFF);

        buf++;

    }

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

    SD_SPI_ReadWriteByte(0xFF);

    SD_SPI_ReadWriteByte(0xFF);                                                                                                                      

    return 0;//读取成功

}

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

//buf:数据缓存区

//cmd:指令

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

u8 SD_SendBlock(u8*buf,u8 cmd)

{        

        u16 t;                            

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

        SD_SPI_ReadWriteByte(cmd);

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

        {

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

            SD_SPI_ReadWriteByte(0xFF);//忽略crc

            SD_SPI_ReadWriteByte(0xFF);

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

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

        }                                                                                                                                                                       

    return 0;//写入成功

}



//向SD卡发送一个命令

//输入: u8 cmd   命令 

//      u32 arg  命令参数

//      u8 crc   crc校验值           

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

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

{

    u8 r1;        

        u8 Retry=0; 

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

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

        //发送

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

    SD_SPI_ReadWriteByte(arg >> 24);

    SD_SPI_ReadWriteByte(arg >> 16);

    SD_SPI_ReadWriteByte(arg >> 8);

    SD_SPI_ReadWriteByte(arg);          

    SD_SPI_ReadWriteByte(crc); 

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

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

        Retry=0X1F;

        do

        {

                r1=SD_SPI_ReadWriteByte(0xFF);

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

        //返回状态值

    return r1;

}                                                                                                                                                                              

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

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

//返回值:0:NO_ERR

//                 1:错误                                                                                                                   

u8 SD_GetCID(u8 *cid_data)

{

    u8 r1;           

    //发CMD10命令,读CID

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

    if(r1==0x00)

        {

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

    }

        SD_DisSelect();//取消片选

        if(r1)return 1;

        else return 0;

}                                                                                                                                                                  

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

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

//返回值:0:NO_ERR

//                 1:错误                                                                                                                   

u8 SD_GetCSD(u8 *csd_data)

{

    u8 r1;         

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

    if(r1==0)

        {

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

    }

        SD_DisSelect();//取消片选

        if(r1)return 1;

        else return 0;

}  

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

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

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

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

u32 SD_GetSectorCount(void)

{

    u8 csd[16];

    u32 Capacity;  

    u8 n;

        u16 csize;                                              

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

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

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

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

    {        

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

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

    }else//V1.XX的卡

    {        

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

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

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

    }

    return Capacity;

}

//初始化SD卡

u8 SD_Initialize(void)

{

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

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

    u8 buf[4];  

        u16 i;



        SD_SPI_Init();                //初始化IO

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

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

        retry=20;

        do

        {

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

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

         SD_Type=0;//默认无卡

        if(r1==0X01)

        {

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

                {

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

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

                        {

                                retry=0XFFFE;

                                do

                                {

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

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

                                }while(r1&&retry--);

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

                                {

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

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

                                        else SD_Type=SD_TYPE_V2;   

                                }

                        }

                }else//SD V1.x/ MMC        V3

                {

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

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

                        if(r1<=1)

                        {                

                                SD_Type=SD_TYPE_V1;

                                retry=0XFFFE;

                                do //等待退出IDLE模式

                                {

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

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

                                }while(r1&&retry--);

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

                        {

                                SD_Type=SD_TYPE_MMC;//MMC V3

                                retry=0XFFFE;

                                do //等待退出IDLE模式

                                {                                                                                            

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

                                }while(r1&&retry--);  

                        }

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

                }

        }

        SD_DisSelect();//取消片选

        SD_SPI_SpeedHigh();//高速

        if(SD_Type)return 0;

        else if(r1)return r1;            

        return 0xaa;//其他错误

}

//读SD卡

//buf:数据缓存区

//sector:扇区

//cnt:扇区数

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

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

{

        u8 r1;

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

        if(cnt==1)

        {

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

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

                {

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

                }

        }else

        {

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

                do

                {

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

                        buf+=512;  

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

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

        }   

        SD_DisSelect();//取消片选

        return r1;//

}

//写SD卡

//buf:数据缓存区

//sector:起始扇区

//cnt:扇区数

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

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

{

        u8 r1;

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

        if(cnt==1)

        {

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

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

                {

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

                }

        }else

        {

                if(SD_Type!=SD_TYPE_MMC)

                {

                        SD_SendCmd(CMD55,0,0X01);        

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

                }

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

                if(r1==0)

                {

                        do

                        {

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

                                buf+=512;  

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

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

                }

        }   

        SD_DisSelect();//取消片选

        return r1;//

}        



//SD test

//#include "malloc.h" 



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

sec:扇区物理地址编号

//void SD_Read_Sectorx(u32 sec)

//{

//        u8 *buf;

//        u16 i;

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

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

//        {        

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

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

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

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

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

//        }

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

//}



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

#include "oled.h"

#include "stdlib.h"

#include "oledfont.h"           

#include "delay.h"



u8 OLED_GRAM[144][8];







具体IIC控制函数

//起始信号

static void I2C_Start(void)

{

        OLED_SDIN_Set();

        OLED_SCLK_Set();

        OLED_SDIN_Clr();

        OLED_SCLK_Clr();

}



//结束信号

static void I2C_Stop(void)

{

        OLED_SCLK_Set();

        OLED_SDIN_Clr();

        OLED_SDIN_Set();

}



//等待信号响应

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

{

        OLED_SCLK_Set();

        OLED_SCLK_Clr();

}



//写入一个字节

static void Send_Byte(u8 dat)

{

        u8 i;

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

        {

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

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

                {

                        OLED_SDIN_Set();

    }

                else

                {

                        OLED_SDIN_Clr();

    }

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

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

                dat<<=1;

  }

}



//发送一个字节

//向SSD1306写入一个字节。

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

void OLED_WR_Byte(u8 dat,u8 mode)

{

        I2C_Start();

        Send_Byte(0x78);

        I2C_WaitAck();

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

  else{Send_Byte(0x00);}

        I2C_WaitAck();

        Send_Byte(dat);

        I2C_WaitAck();

        I2C_Stop();

}





//反显函数

void OLED_ColorTurn(u8 i)

{

        if(i==0)

                {

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

                }

        if(i==1)

                {

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

                }

}



//屏幕旋转180度

void OLED_DisplayTurn(u8 i)

{

        if(i==0)

                {

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

                        OLED_WR_Byte(0xA1,OLED_CMD);

                }

        if(i==1)

                {

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

                        OLED_WR_Byte(0xA0,OLED_CMD);

                }

}





//开启OLED显示 

void OLED_DisPlay_On(void)

{

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

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

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

}



//关闭OLED显示 

void OLED_DisPlay_Off(void)

{

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

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

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

}



//更新显存到OLED        

void OLED_Refresh(void)

{

        u8 i,n;

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

        {

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

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

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

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

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

  }

}

//自定义清屏函数

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

{

        u8 i,n;

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

        {

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

                        {

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

                        }

  }

        OLED_Refresh();//更新显示

}

//清屏函数

void OLED_Clear(void)

{

        u8 i,n;

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

        {

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

                        {

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

                        }

  }

        OLED_Refresh();//更新显示

}



//画点 

//x:0~127

//y:0~63

void OLED_DrawPoint(u8 x,u8 y)

{

        u8 i,m,n;

        i=y/8;

        m=y%8;

        n=1<<m;

        OLED_GRAM[x][i]|=n;

}



//清除一个点

//x:0~127

//y:0~63

void OLED_ClearPoint(u8 x,u8 y)

{

        u8 i,m,n;

        i=y/8;

        m=y%8;

        n=1<<m;

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

        OLED_GRAM[x][i]|=n;

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

}





//画线

//x:0~128

//y:0~64

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

{

        u8 i,k,k1,k2;

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

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

        {

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

                        {

                                OLED_DrawPoint(x1,y1+i);

                        }

  }

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

        {

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

                        {

                                OLED_DrawPoint(x1+i,y1);

                        }

  }

        else      //画斜线

        {

                k1=y2-y1;

                k2=x2-x1;

                k=k1*10/k2;

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

                        {

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

                        }

        }

}

//x,y:圆心坐标

//r:圆的半径

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

{

        int a, b,num;

    a = 0;

    b = r;

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

    {

        OLED_DrawPoint(x + a, y - b);

        OLED_DrawPoint(x - a, y - b);

        OLED_DrawPoint(x - a, y + b);

        OLED_DrawPoint(x + a, y + b);

 

        OLED_DrawPoint(x + b, y + a);

        OLED_DrawPoint(x + b, y - a);

        OLED_DrawPoint(x - b, y - a);

        OLED_DrawPoint(x - b, y + a);

        

        a++;

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

        if(num > 0)

        {

            b--;

            a--;

        }

    }

}







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

//x:0~127

//y:0~63

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

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

{

        u8 i,m,temp,size2,chr1;

        u8 y0=y;

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

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

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

        {

                if(size1==12)

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

                else if(size1==16)

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

                else if(size1==24)

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

                else return;

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

                                {

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

                                        else OLED_ClearPoint(x,y);

                                        temp<<=1;

                                        y++;

                                        if((y-y0)==size1)

                                        {

                                                y=y0;

                                                x++;

                                                break;

          }

                                }

  }

}





//显示字符串

//x,y:起点坐标  

//size1:字体大小 

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

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

{

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

        {

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

                x+=size1/2;

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

                {

                        x=0;

                        y+=2;

    }

                chr++;

  }

}



//m^n

u32 OLED_Pow(u8 m,u8 n)

{

        u32 result=1;

        while(n--)

        {

          result*=m;

        }

        return result;

}



显示2个数字

x,y :起点坐标         

len :数字的位数

size:字体大小

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

{

        u8 t,temp;

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

        {

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

                        if(temp==0)

                        {

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

      }

                        else 

                        {

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

                        }

  }

}



//显示汉字

//x,y:起点坐标

//num:汉字对应的序号

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

{

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

        u8 x0=x,y0=y;

        u8 size3=size1/8;

        while(size3--)

        {

                chr1=num*size1/8+n;

                n++;

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

                        {

                                if(size1==16)

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

                                else if(size1==24)

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

                                else if(size1==32)       

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

                                else if(size1==64)

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

                                else return;

                                                        

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

                                                        {

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

                                                                else OLED_ClearPoint(x,y);

                                                                temp>>=1;

                                                                y++;

                                                        }

                                                        x++;

                                                        if((x-x0)==size1)

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

                                                        y=y0;

                         }

        }

}



//num 显示汉字的个数

//space 每一遍显示的间隔

void OLED_ScrollDisplay(u8 num,u8 space)

{

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

        while(1)

        {

                if(m==0)

                {

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

                        t++;

                }

                if(t==num)

                        {

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

                                 {

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

                                                {

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

                                                        {

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

                                                        }

                                                }

           OLED_Refresh();

                                 }

        t=0;

      }

                m++;

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

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

                {

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

                        {

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

                        }

                }

                OLED_Refresh();

        }

}



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

void OLED_WR_BP(u8 x,u8 y)

{

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

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

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

}



//x0,y0:起点坐标

//x1,y1:终点坐标

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

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

{

        u32 j=0;

        u8 x=0,y=0;

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

        else y+=1;

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

         {

                 OLED_WR_BP(x0,y);

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

                 {

                         OLED_WR_Byte(BMP[j],OLED_DATA);

                         j++;

     }

         }

}

//OLED的初始化

void OLED_Init(void)

{

        GPIO_InitTypeDef  GPIO_InitStructure;

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

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5;         

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

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

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

         GPIO_SetBits(GPIOC,GPIO_Pin_4|GPIO_Pin_5);        

        

        delay_ms(200);

        

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        OLED_WR_Byte(0x12,OLED_CMD);

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

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

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

        OLED_WR_Byte(0x02,OLED_CMD);//

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

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

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

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

        OLED_WR_Byte(0xAF,OLED_CMD);

        OLED_Clear();

}

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

  //OLED

    OLED_Init();

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

    OLED_Refresh();

    //24CXX

    AT24CXX_Init();                        //IIC初始化 

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

    {

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

        delay_ms(500);

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

        delay_ms(500);

        LED0=!LED0;//DS0闪烁

        OLED_Refresh();

    }

    OLED_Clear();

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

    OLED_Refresh();

    //OLED TEST

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

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

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

    OLED_Refresh();

    delay_ms(5000);

    OLED_Clear();

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

    AT24CXX_Read(0,datatemp,SIZE);

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

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

    OLED_Refresh();

    delay_ms(500);



    //FLASH

    W25QXX_Init();                        //W25QXX初始化

    OLED_Clear();

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

    {

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

        delay_ms(500);

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

        delay_ms(500);

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

        OLED_Refresh();

        LED0=!LED0;//DS0闪烁

    }

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

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

    OLED_Refresh();  

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

    //W25Q64 TEST

    OLED_Clear();

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

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

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

    OLED_Refresh();

    delay_ms(5000);

    OLED_Clear();

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

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

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

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

    OLED_Refresh();

    delay_ms(500);

    //SD TEST

    OLED_Clear();

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

        {

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

        OLED_Refresh();

                delay_ms(500);                                        

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

        OLED_Refresh();

                delay_ms(500);

                LED0=!LED0;//DS0闪烁

        }

    //检测SD卡成功 

    OLED_Clear();    

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

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

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

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

    OLED_Refresh();


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

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值