代码拉取完成,页面将自动刷新
同步操作将从 天伟/stm32f103c_i2c_dma_oled 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
/************************************************************************************
* Author :firestaradmin
* Date :2019.6.4
* Description : 128*64点阵的OLED显示屏驱动文件,仅适用于SD1306驱动IIC通信方式显示屏
2019.12.11 :增加了DMA IIC传输模式,增加了传输速度,降低CPU负担。
2019.11.08 :更新为显存模式驱动屏幕,支持画点画线等需求,方便UI设计,动画显示。
2019.11.06 :优化IIC传输步骤,一次传输全部数据,增加整屏刷新速率,帧率可达40~50帧每秒。并增加定时器定时刷新模式。
根据坊间流传硬件i2c可能出现卡死现象,不过用这个库我好像没出现过这现象, 要是真遇到了解决办法请网上找找
oled资料 https://blog.csdn.net/Keep_moving_tzw/article/details/104877286
*
*************************************************************************************/
#include "oled.h"
#include "Delay.h"
#include "oled_font.h"
#include "stdio.h"
#include <string.h>
u8 OLED_GRAM[8][128] = {0}; //定义模拟显存
u8 g_OLED_GRAM_State = 0; //SRAM模拟显存更新完毕标志位
u8 g_OLED_DMA_BusyFlag = 0; //DMA忙碌标志位
char runModeStr[50] = {0}; //用于显示 运行在哪种模式
//配置硬件i2c
void I2C_Configuration(void)
{
I2C_InitTypeDef I2C_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//开启时钟
RCC_APB1PeriphClockCmd(OLED_I2C_RCC_Periph,ENABLE);
RCC_APB2PeriphClockCmd(OLED_GPIO_RCC_Periph,ENABLE);
/* STM32F103C8T6芯片的硬件 I2C: PB6 -- SCL; PB7 -- SDA */
GPIO_InitStructure.GPIO_Pin = OLED_SCL | OLED_SDA;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; //I2C必须开漏输出
GPIO_Init(OLED_IIC_GPIO, &GPIO_InitStructure);
I2C_DeInit(OLED_HardWare_IIC);//使用I2C1
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x30; //主机的I2C地址,随便写的
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 400000;//400Khz
//开启i2c
I2C_Init(OLED_HardWare_IIC, &I2C_InitStructure);
I2C_Cmd(OLED_HardWare_IIC, ENABLE);
}
//i2c写byte数据
void I2C_WriteByte(uint8_t addr,uint8_t data)
{
while(I2C_GetFlagStatus(OLED_HardWare_IIC, I2C_FLAG_BUSY));
I2C_GenerateSTART(OLED_HardWare_IIC, ENABLE);//开启I2C1
while(!I2C_CheckEvent(OLED_HardWare_IIC, I2C_EVENT_MASTER_MODE_SELECT));/*EV5,主模式*/
I2C_Send7bitAddress(OLED_HardWare_IIC, OLED_ADDRESS, I2C_Direction_Transmitter);//器件地址 -- 默认0x78
while(!I2C_CheckEvent(OLED_HardWare_IIC, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(OLED_HardWare_IIC, addr);//寄存器地址
while (!I2C_CheckEvent(OLED_HardWare_IIC, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_SendData(OLED_HardWare_IIC, data);//发送数据
while (!I2C_CheckEvent(OLED_HardWare_IIC, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(OLED_HardWare_IIC, ENABLE);//关闭I2C1总线
}
void WriteCmd(unsigned char I2C_Command) //写命令给oled
{
I2C_WriteByte(0x00, I2C_Command);
}
void WriteDat(unsigned char I2C_Data) //写数据给oled
{
I2C_WriteByte(0x40, I2C_Data);
}
void OLED_WR_Byte(u8 dat, u8 cmd)
{
I2C_WriteByte(cmd, dat);
}
//oled初始化
void OLED_Init(void)
{
//初始化i2c
I2C_Configuration();
Delay_ms(50); //这里的延时很重要
//开始oled命令
WriteCmd(0xae);//关闭显示
WriteCmd(0xd5); //设置时钟分频因子,震荡频率
WriteCmd(0x80); //[3:0],分频因子;[7:4],震荡频率
WriteCmd(0x81);//设置对比度
WriteCmd(0xff); //亮度调节 0x00~0xff
WriteCmd(0x8d);//设置电荷泵开关
WriteCmd(0x14);//开
WriteCmd(0x20);//设置模式
WriteCmd(0x00);//设置为水平地址模式
WriteCmd(0x21); //设置列地址的起始和结束的位置
WriteCmd(0x0); //0
WriteCmd(0x7f);//127
WriteCmd(0x22);//设置页地址的起始和结束的位置
WriteCmd(0x0);//0
WriteCmd(0x07);//7
WriteCmd(0xc8);//0xc9上下反置 0xc8正常
WriteCmd(0xa1);//0xa0左右反置 0xa1正常
WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
WriteCmd(0xaf);//开启显示
WriteCmd(0xa6); // 设置显示方式;bit0:1,反相显示;0,正常显示
//是否启用dma
#ifdef OLED_DMA_Trans
//用的话初始化下配置下dma
MYDMA_Config(DMA1_Channel6, (u32)&OLED_HardWare_IIC->DR,(u32)OLED_GRAM, 1025); //DMA1通道4,外设为I2C1,存储器为OLED_GRAM,长度128*8 = 1024.
I2C_DMACmd(OLED_HardWare_IIC, ENABLE); //使能I2C1 的 DMA请求
#endif
}
//--------------------------------------------------------------
// Prototype : void OLED_ON(void)
// Calls :
// Parameters : none
// Description : 将OLED从休眠中唤醒
//--------------------------------------------------------------
void OLED_ON(void)
{
WriteCmd(0X8D); //设置电荷泵
WriteCmd(0X14); //开启电荷泵
WriteCmd(0XAF); //OLED唤醒
}
//--------------------------------------------------------------
// Prototype : void OLED_OFF(void)
// Calls :
// Parameters : none
// Description : 让OLED休眠 -- 休眠模式下,OLED功耗不到10uA
//--------------------------------------------------------------
void OLED_OFF(void)
{
WriteCmd(0X8D); //设置电荷泵
WriteCmd(0X10); //关闭电荷泵
WriteCmd(0XAE); //OLED休眠
}
//IIC ssd1306 传输数据时 可以一个命令 接多个数据 节省很多时间
//u8 OLED_GRAM[8][128];
void OLED_Refresh_OneTime(void)
{
#ifdef OLED_DMA_Trans
if(g_OLED_DMA_BusyFlag == 0)
{
while(I2C_GetFlagStatus(OLED_HardWare_IIC, I2C_FLAG_BUSY));
I2C_GenerateSTART(OLED_HardWare_IIC, ENABLE);//开启I2C1
while(!I2C_CheckEvent(OLED_HardWare_IIC, I2C_EVENT_MASTER_MODE_SELECT));/*EV5,主模式*/
I2C_Send7bitAddress(OLED_HardWare_IIC, OLED_ADDRESS, I2C_Direction_Transmitter);//器件地址 -- 默认0x78
while(!I2C_CheckEvent(OLED_HardWare_IIC, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(OLED_HardWare_IIC, OLED_DATA);//寄存器地址
while (!I2C_CheckEvent(OLED_HardWare_IIC, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
//设置忙碌等待DMA执行完成
g_OLED_DMA_BusyFlag = 1;
g_OLED_GRAM_State = 1;
//开始dma传递数据
MYDMA_Enable(DMA1_Channel6);
}
sprintf(runModeStr, "%s", "i2c+dma mode");
#else
g_OLED_GRAM_State = 1; //设置在显存更新标志位
u8 i = 0 ,j =0;
while(I2C_GetFlagStatus(OLED_HardWare_IIC, I2C_FLAG_BUSY));
I2C_GenerateSTART(OLED_HardWare_IIC, ENABLE);//开启I2C1
while(!I2C_CheckEvent(OLED_HardWare_IIC, I2C_EVENT_MASTER_MODE_SELECT));/*EV5,主模式*/
I2C_Send7bitAddress(OLED_HardWare_IIC, OLED_ADDRESS, I2C_Direction_Transmitter);//器件地址 -- 默认0x78
while(!I2C_CheckEvent(OLED_HardWare_IIC, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(OLED_HardWare_IIC, OLED_DATA);//寄存器地址
while (!I2C_CheckEvent(OLED_HardWare_IIC, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
for(i = 0; i < 8; i++)
{
for(j = 0;j<128;j++)
{
I2C_SendData(OLED_HardWare_IIC, OLED_GRAM[i][j]);//发送数据
while (!I2C_CheckEvent(OLED_HardWare_IIC, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}
}
I2C_GenerateSTOP(OLED_HardWare_IIC, ENABLE);//关闭I2C1总线
g_OLED_GRAM_State = 0; //清除显存更新标志位
sprintf(runModeStr, "%s", "i2c mode");
#endif
}
//--------------------------------------------------------------
// Prototype : void OLED_ShowINT(u8 x, u8 y, int num, u8 size, u8 mode)
// Calls :
// Parameters : x,y -- 起始点坐标(x:0~127, y:0~63); int num 显示的int整型; Size:字号(12/16/24)
// mode:0(OLED_DISPLAYCHAR_REVERSE)反白显示;1(OLED_DISPLAYCHAR_NORMAL),正常显示
// Description :
//--------------------------------------------------------------
void OLED_ShowINT(u8 x, u8 y, int num, u8 size, u8 mode)
{
unsigned char *ch = my_itoa(num);
OLED_ShowString(x, y, ch, size, mode);
}
//--------------------------------------------------------------
// Prototype : void OLED_ShowFLOAT(u8 x, u8 y, float num, u8 pointNum,u8 size, u8 mode)
// Calls :
// Parameters : x,y -- 起始点坐标(x:0~127, y:0~63); float num 显示的float型;
// pointNum : 小数点后保留位数(0~5)
// Size:字号(12/16/24)
// mode:0(OLED_DISPLAYCHAR_REVERSE)反白显示;1(OLED_DISPLAYCHAR_NORMAL),正常显示
// Description :
//--------------------------------------------------------------
void OLED_ShowFLOAT(u8 x, u8 y, float num, u8 pointNum,u8 size, u8 mode)
{
unsigned char ch1[50],ch2[50];
unsigned char *ptemp;
unsigned i=0,j=0;
long t1,t2;
float ftemp;
t1 = num/1;
ftemp = num - t1;
for(i = 0; i < pointNum;i++)
{
ftemp *= 10;
}
t2 = (long)ftemp;
ptemp = my_itoa(t1);
for(i = 0; i < 50;i++) ch1[i] = *ptemp++;
ptemp = my_itoa(t2);
for(i = 0; i < 50;i++) ch2[i] = *ptemp++;
while(ch1[j] != '\0')
{
j++;
}
ch1[j] = '.';
ptemp = my_strcat(ch1, ch2);
OLED_ShowString(x, y, ptemp, size, mode);
}
/**
* 函 数:将OLED显存数组部分清零
* 参 数:X 指定区域左上角的横坐标,范围:0~127
* 参 数:Y 指定区域左上角的纵坐标,范围:0~63
* 参 数:Width 指定区域的宽度,范围:0~128
* 参 数:Height 指定区域的高度,范围:0~64
* 返 回 值:无
* 说 明:调用此函数后,要想真正地呈现在屏幕上,还需调用更新函数
*/
void OLED_ClearArea(uint8_t X, uint8_t Y, uint8_t Width, uint8_t Height)
{
uint8_t i, j;
/*参数检查,保证指定区域不会超出屏幕范围*/
if (X > 127) {return;}
if (Y > 63) {return;}
if (X + Width > 128) {Width = 128 - X;}
if (Y + Height > 64) {Height = 64 - Y;}
for (j = Y; j < Y + Height; j ++) //遍历指定页
{
for (i = X; i < X + Width; i ++) //遍历指定列
{
OLED_GRAM[j / 8][i] &= ~(0x01 << (j % 8)); //将显存数组指定数据清零
}
}
}
/*********************************************
Function :void OLED_RamClear(void)
Description:将GRAM全置为0 清空显存
Input : void
Return : void
Author : firestaradmin
**********************************************/
void OLED_RamClear(void)
{
u8 i,n;
for(i=0;i<8;i++)for(n=0;n<128;n++)OLED_GRAM[i][n]=0x00;
}
void OLED_Clear(void)
{
OLED_RamClear();
OLED_Refresh_OneTime();//更新显示
}
//画点
//x:0~127
//y:0~63
//t:1(OLED_LED_LIGHTUP) 填充 ; 0(OLED_LED_EXTINGUISH),清空
void OLED_DrawPoint(u8 x,u8 y,u8 t)
{
u8 pos,bx,temp=0;
if(x>127||y>63)return;//超出范围了.
pos=y/8;
bx=y%8;
temp=1<<bx;
if(t)OLED_GRAM[pos][x]|=temp;
else OLED_GRAM[pos][x]&=~temp;
}
//x1,y1,x2,y2 填充区域的对角坐标
//确保x1<=x2;y1<=y2 0<=x1<=127 0<=y1<=63
//t:1(OLED_LED_LIGHTUP) 填充 ; 0(OLED_LED_EXTINGUISH),清空
void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot)
{
u8 x,y;
for(x=x1;x<=x2;x++)
{
for(y=y1;y<=y2;y++)OLED_DrawPoint(x,y,dot);
}
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0(OLED_DISPLAYCHAR_REVERSE)反白显示;1(OLED_DISPLAYCHAR_NORMAL),正常显示
//size:选择字体 12/16/24 (列高)
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode)
{
u8 temp,t,t1;
u8 y0=y;
u8 csize=(size/8+((size%8)?1:0))*(size/2); //得到字体一个字符对应点阵集所占的字节数
chr=chr-' ';//得到偏移后的值
if(size == 8)csize = 5;
for(t=0;t<csize;t++)
{
if(size==12)temp=asc2_1206[chr][t]; //调用1206字体
else if(size==16)temp=asc2_1608[chr][t]; //调用1608字体
else if(size==24)temp=asc2_2412[chr][t]; //调用2412字体
else return; //没有的字库
for(t1=0;t1<8;t1++)
{
if(temp&0x80)OLED_DrawPoint(x,y,mode);
else OLED_DrawPoint(x,y,!mode);
temp<<=1;
y++;
if((y-y0)==size)
{
y=y0;
x++;
break;
}
}
}
}
//显示字符串
//x,y:起点坐标
//*p:字符串起始地址
//mode:0(OLED_DISPLAYCHAR_REVERSE)反白显示;1(OLED_DISPLAYCHAR_NORMAL),正常显示
//size:选择字体 12/16/24
void OLED_ShowString(u8 x,u8 y,const u8 *p,u8 size, u8 mode)
{
//u8 csize=(size/8+((size%8)?1:0))*(size/2);
if(size != 8)
{
while(*p!='\0')
{
if(x>OLED_PIXEL_X-(size/2)+1){x=0;y+=size;}
if(y>OLED_PIXEL_Y-size+1){y=x=0;}
OLED_ShowChar(x,y,*p,size,mode);
x+=size/2;
p++;
}
}
else
{
while(*p!='\0')
{
if(x>OLED_PIXEL_X-(size/2)+1){x=0;y+=size;}
if(y>OLED_PIXEL_Y-size+1){y=x=0;}
OLED_ShowChar(x,y,*p,size,mode);
x+=5;
p++;
}
}
}
/**
* 函 数:OLED显示图像
* 参 数:X 指定图像左上角的横坐标,范围:0~127
* 参 数:Y 指定图像左上角的纵坐标,范围:0~63
* 参 数:Width 指定图像的宽度,范围:0~128
* 参 数:Height 指定图像的高度,范围:0~64
* 参 数:Image 指定要显示的图像
* 返 回 值:无
* 说 明:调用此函数后,要想真正地呈现在屏幕上,还需调用更新函数
*/
void OLED_ShowImage(uint8_t X, uint8_t Y, uint8_t Width, uint8_t Height, const uint8_t *Image)
{
uint8_t i, j;
/*参数检查,保证指定图像不会超出屏幕范围*/
if (X > 127) {return;}
if (Y > 63) {return;}
/*将图像所在区域清空*/
OLED_ClearArea(X, Y, Width, Height);
/*遍历指定图像涉及的相关页*/
/*(Height - 1) / 8 + 1的目的是Height / 8并向上取整*/
for (j = 0; j < (Height - 1) / 8 + 1; j ++)
{
/*遍历指定图像涉及的相关列*/
for (i = 0; i < Width; i ++)
{
/*超出边界,则跳过显示*/
if (X + i > 127) {break;}
if (Y / 8 + j > 7) {return;}
/*显示图像在当前页的内容*/
OLED_GRAM[Y / 8 + j][X + i] |= Image[j * Width + i] << (Y % 8);
/*超出边界,则跳过显示*/
/*使用continue的目的是,下一页超出边界时,上一页的后续内容还需要继续显示*/
if (Y / 8 + j + 1 > 7) {continue;}
/*显示图像在下一页的内容*/
OLED_GRAM[Y / 8 + j + 1][X + i] |= Image[j * Width + i] >> (8 - Y % 8);
}
}
}
//显示中文字符
//x,y:起点坐标
//N:文字
//mode:0(OLED_DISPLAYCHAR_REVERSE)反白显示;1(OLED_DISPLAYCHAR_NORMAL),正常显示
void OLED_Show16X16oneCN(uint8_t X, uint8_t Y, char *Chinese, u8 mode)
{
uint8_t pChinese = 0;
uint8_t pIndex;
uint8_t i;
char SingleChinese[OLED_CHN_CHAR_WIDTH + 1] = {0};
uint8_t reverseArr[32] = {0}; //反转用的
uint16_t ni = 0;
for (i = 0; Chinese[i] != '\0'; i ++) //遍历汉字串
{
SingleChinese[pChinese] = Chinese[i]; //提取汉字串数据到单个汉字数组
pChinese ++; //计次自增
/*当提取次数到达OLED_CHN_CHAR_WIDTH时,即代表提取到了一个完整的汉字*/
if (pChinese >= OLED_CHN_CHAR_WIDTH)
{
pChinese = 0; //计次归零
/*遍历整个汉字字模库,寻找匹配的汉字*/
/*如果找到最后一个汉字(定义为空字符串),则表示汉字未在字模库定义,停止寻找*/
for (pIndex = 0; strcmp(OLED_CF16x16[pIndex].Index, "") != 0; pIndex ++)
{
/*找到匹配的汉字*/
if (strcmp(OLED_CF16x16[pIndex].Index, SingleChinese) == 0)
{
break; //跳出循环,此时pIndex的值为指定汉字的索引
}
}
/*将汉字字模库OLED_CF16x16的指定数据以16*16的图像格式显示*/
if(mode == OLED_DISPLAYCHAR_REVERSE){ //反白模式
for(int ni=0; ni<32; ni++){ //默认32个字节
reverseArr[ni] = ~OLED_CF16x16[pIndex].Data[ni];
}
OLED_ShowImage(X + ((i + 1) / OLED_CHN_CHAR_WIDTH - 1) * 16, Y, 16, 16, reverseArr);
}else{ //正常模式
OLED_ShowImage(X + ((i + 1) / OLED_CHN_CHAR_WIDTH - 1) * 16, Y, 16, 16, OLED_CF16x16[pIndex].Data);
}
}
}
}
//画线函数
//起点x1 y1 ;终点x2 y2
//color 1 亮 ;0 灭
void OLED_DrawLine(int x1,int y1,int x2,int y2,int color)
{
int dx,dy,e;
dx=x2-x1;
dy=y2-y1;
if(dx>=0)
{
if(dy >= 0) // dy>=0
{
if(dx>=dy) // 1/8 octant
{
e=dy-dx/2;
while(x1<=x2)
{
OLED_DrawPoint(x1,y1,color);
if(e>0){y1+=1;e-=dx;}
x1+=1;
e+=dy;
}
}
else // 2/8 octant
{
e=dx-dy/2;
while(y1<=y2)
{
OLED_DrawPoint(x1,y1,color);
if(e>0){x1+=1;e-=dy;}
y1+=1;
e+=dx;
}
}
}
else // dy<0
{
dy=-dy; // dy=abs(dy)
if(dx>=dy) // 8/8 octant
{
e=dy-dx/2;
while(x1<=x2)
{
OLED_DrawPoint(x1,y1,color);
if(e>0){y1-=1;e-=dx;}
x1+=1;
e+=dy;
}
}
else // 7/8 octant
{
e=dx-dy/2;
while(y1>=y2)
{
OLED_DrawPoint(x1,y1,color);
if(e>0){x1+=1;e-=dy;}
y1-=1;
e+=dx;
}
}
}
}
else //dx<0
{
dx=-dx; //dx=abs(dx)
if(dy >= 0) // dy>=0
{
if(dx>=dy) // 4/8 octant
{
e=dy-dx/2;
while(x1>=x2)
{
OLED_DrawPoint(x1,y1,color);
if(e>0){y1+=1;e-=dx;}
x1-=1;
e+=dy;
}
}
else // 3/8 octant
{
e=dx-dy/2;
while(y1<=y2)
{
OLED_DrawPoint(x1,y1,color);
if(e>0){x1-=1;e-=dy;}
y1+=1;
e+=dx;
}
}
}
else // dy<0
{
dy=-dy; // dy=abs(dy)
if(dx>=dy) // 5/8 octant
{
e=dy-dx/2;
while(x1>=x2)
{
OLED_DrawPoint(x1,y1,color);
if(e>0){y1-=1;e-=dx;}
x1-=1;
e+=dy;
}
}
else // 6/8 octant
{
e=dx-dy/2;
while(y1>=y2)
{
OLED_DrawPoint(x1,y1,color);
if(e>0){x1-=1;e-=dy;}
y1-=1;
e+=dx;
}
}
}
}
}
//-------------画圆函数。参数:圆心,半径,颜色----------
// 画1/8圆 然后其他7/8对称画
// ---------------->X
// |(0,0) 0
// | 7 1
// | 6 2
// | 5 3
// (Y)V 4
//
// L = x^2 + y^2 - r^2
void OLED_DrawCircle(int x, int y, int r, int color)
{
int a, b, num;
a = 0;
b = r;
while(2 * b * b >= r * r) // 1/8圆即可
{
OLED_DrawPoint(x + a, y - b,color); // 0~1
OLED_DrawPoint(x - a, y - b,color); // 0~7
OLED_DrawPoint(x - a, y + b,color); // 4~5
OLED_DrawPoint(x + a, y + b,color); // 4~3
OLED_DrawPoint(x + b, y + a,color); // 2~3
OLED_DrawPoint(x + b, y - a,color); // 2~1
OLED_DrawPoint(x - b, y - a,color); // 6~7
OLED_DrawPoint(x - b, y + a,color); // 6~5
a++;
num = (a * a + b * b) - r*r;
if(num > 0)
{
b--;
a--;
}
}
}
void OLED_DrawRectangle(u8 x1,u8 y1,u8 x2,u8 y2,u8 mode)
{
OLED_DrawLine(x1,y1,x2,y1,mode);
OLED_DrawLine(x1,y1,x1,y2,mode);
OLED_DrawLine(x2,y2,x2,y1,mode);
OLED_DrawLine(x2,y2,x1,y2,mode);
}
//********************************************************************************************************
//========================================DMA1=======================================================
u16 DMA1_MEM_LEN;//保存DMA每次数据传送的长度
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量
void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar, u16 cndtr)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输
DMA_DeInit(DMA_CHx); //将DMA的通道1寄存器重设为缺省值
DMA1_MEM_LEN=cndtr;
DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设基地址
DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向,从内存读取发送到外设 外设作为目的地
DMA_InitStructure.DMA_BufferSize = cndtr; //DMA通道的DMA缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为8位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常模式 //DMA_Mode_Circular; //工作在循环传输模式 //DMA_Mode_Normal; //工作在正常模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
DMA_Init(DMA_CHx, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道所标识的寄存器
NVIC_InitTypeDef NVIC_InitStructure;
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn; //DMA中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //从优先级1级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
/* Enable DMA Channelx complete transfer interrupt */
DMA_ITConfig(DMA_CHx, DMA_IT_TC, ENABLE);
}
//开启一次DMA传输
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
DMA_Cmd(DMA_CHx, DISABLE ); //关闭 DMA 所指示的通道
DMA_SetCurrDataCounter(DMA_CHx, DMA1_MEM_LEN);//DMA通道的DMA缓存的大小
DMA_Cmd(DMA_CHx, ENABLE); //使能 DMA 所指示的通道
}
//dma完成后的回调
void DMA1_Channel6_IRQHandler(void)
{
if(DMA_GetFlagStatus(DMA1_FLAG_TC6))
{
/* Clear the DMA Channel3 transfer error interrupt pending bit */
DMA_ClearFlag(DMA1_FLAG_TC6);
I2C_GenerateSTOP(OLED_HardWare_IIC, ENABLE);//关闭I2C1总线
g_OLED_GRAM_State = 0; //清楚显存更新标志位
g_OLED_DMA_BusyFlag = 0;//复位忙碌标志
}
}
//********************************************************************************************************
/*********************************************
Function: unsigned char *reverse(unsigned char *s)
Description:将字符串顺序颠倒
Input: unsigned char * :要颠倒的字符串
Return: unsigned char* :转换后的字符串指针
Author: firestaradmin
**********************************************/
unsigned char *reverse(unsigned char *s)
{
unsigned char temp;
unsigned char *p = s; //p指向s的头部
unsigned char *q = s; //q指向s的尾部
while(*q)
++q;
q--;
//交换移动指针,直到p和q交叉
while(q > p)
{
temp = *p;
*p++ = *q;
*q-- = temp;
}
return s;
}
/*********************************************
Function: unsigned char *my_itoa(int n)
Description:将int型转换为unsigned char*字符串
Input: int n :要转换的数
Return: unsigned char* :转换后的字符串指针
Calls: unsigned char *reverse(unsigned char *s)
Author: firestaradmin
**********************************************/
unsigned char *my_itoa(long n)
{
int i = 0,isNegative = 0;
static unsigned char s[50]; //必须为static变量,或者是全局变量
if((isNegative = n) < 0) //如果是负数,先转为正数
{
n = -n;
}
do //从各位开始变为字符,直到最高位,最后应该反转
{
s[i++] = n%10 + '0';
n = n/10;
}while(n > 0);
if(isNegative < 0) //如果是负数,补上负号
{
s[i++] = '-';
}
s[i] = '\0'; //最后加上字符串结束符
return reverse(s);
}
/*********************************************
Function: unsigned char *my_strcat(u8 * str1, u8 * str2)
Description:将str2拼接到str1末尾
Input: str1 str2
Return: unsigned char* :转换后的字符串指针
Calls:
Author: firestaradmin
**********************************************/
unsigned char *my_strcat(u8 * str1, u8 * str2)
{
u8* pt = str1;
while(*str1 != '\0') str1++;
while(*str2 != '\0') *str1++ = *str2++;
*str1 = '\0';
return pt;
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。