0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

AT89S52单片机入门

科技绿洲 来源:gaoyang9992006 作者:gaoyang9992006 2023-09-11 10:03 次阅读

最近捡到一个十几年前学单片机时候的入门单片机:AT89S52。

我觉得我应该做点什么,于是便去翻腾垃圾,又捡到一片DS1302;再从一个玩具上拆下一个32.768KHZ晶振,找到一片0.91寸I2C接口OLED,还有一个ADC,TLC2543,DS12887……然后就去嘉立创“薅羊毛”打了一个板子开始玩起来

3D效果图:

图片

实物图:

图片

以前做什么都是本着能用就好的拿来主义,很少去深度思考人家是怎么写的。比如这个OLED模块,大部分都是用厂家提供的那一套,没有思考是怎么写的,底层是怎么实现的,也就是不重复造轮子。

然而我今天闲了,想要看看轮子怎么造的,最后也要仿造人家的轮子做个零件出来

1、I2C的基础操作函数

首先,看了一下厂家提供的示例,比如51单片机用IO模拟I2C的基础函数有:起始信号、结束信号、等待信号响应。

//起始信号
void I2C_Start(void)
{
OLED_SDA_Set();
OLED_SCL_Set();
IIC_delay();
OLED_SDA_Clr();
IIC_delay();
OLED_SCL_Clr();


}


//结束信号
void I2C_Stop(void)
{
OLED_SDA_Clr();
OLED_SCL_Set();
IIC_delay();
OLED_SDA_Set();
}


//等待信号响应
void I2C_WaitAck(void) //测数据信号的电平
{
OLED_SDA_Set();
IIC_delay();
OLED_SCL_Set();
IIC_delay();
OLED_SCL_Clr();
IIC_delay();
}

2、I2C的字节写入函数:写入一个字节

//写入一个字节
void Send_Byte(u8 dat)
{
u8 i;
for(i=0;i< 8;i++)
{
OLED_SCL_Clr();//将时钟信号设置为低电平
if(dat&0x80)//将dat的8位从最高位依次写入
{
OLED_SDA_Set();
}
else
{
OLED_SDA_Clr();
}
IIC_delay();
OLED_SCL_Set();
IIC_delay();
OLED_SCL_Clr();
dat< <=1;
}
}

3、给OLED写入指令或数据

接下来,在以上的基础函数前提下可以操作OLED了,通过以上的组合可以实现给OLED写入指令或数据。

//发送一个字节
//向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();
}

4、利用基础的写入操作可以实现上层次的传送各种指令和数据给OLED的控制器SSD1306了

/*
坐标设置,对于128*32分辨率的OLED:x从127;y从0到3
*/


void OLED_Set_Pos(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),OLED_CMD);
}
//开启OLED显示
void OLED_Display_On(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X14,OLED_CMD); //DCDC ON
OLED_WR_Byte(0XAF,OLED_CMD); //DISPLAY ON
}
//关闭OLED显示
void OLED_Display_Off(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFF
OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF
}
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
void OLED_Clear(void)
{
u8 i,n;
for(i=0;i< 4;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n< 128;n++)OLED_WR_Byte(0,OLED_DATA);
} //更新显示
}






//初始化
void OLED_Init(void)
{


OLED_WR_Byte(0xAE,OLED_CMD); /*display off*/
OLED_WR_Byte(0x00,OLED_CMD); /*set lower column address*/
OLED_WR_Byte(0x10,OLED_CMD); /*set higher column address*/
OLED_WR_Byte(0x00,OLED_CMD); /*set display start line*/
OLED_WR_Byte(0xB0,OLED_CMD); /*set page address*/
OLED_WR_Byte(0x81,OLED_CMD); /*contract control*/
OLED_WR_Byte(0xff,OLED_CMD); /*128*/
OLED_WR_Byte(0xA1,OLED_CMD); /*set segment remap*/
OLED_WR_Byte(0xA6,OLED_CMD); /*normal / reverse*/
OLED_WR_Byte(0xA8,OLED_CMD); /*multiplex ratio*/
OLED_WR_Byte(0x1F,OLED_CMD); /*duty = 1/32*/
OLED_WR_Byte(0xC8,OLED_CMD); /*Com scan direction*/
OLED_WR_Byte(0xD3,OLED_CMD); /*set display offset*/
OLED_WR_Byte(0x00,OLED_CMD);
OLED_WR_Byte(0xD5,OLED_CMD); /*set osc division*/
OLED_WR_Byte(0x80,OLED_CMD);
OLED_WR_Byte(0xD9,OLED_CMD); /*set pre-charge period*/
OLED_WR_Byte(0x1f,OLED_CMD);
OLED_WR_Byte(0xDA,OLED_CMD); /*set COM pins*/
OLED_WR_Byte(0x00,OLED_CMD);
OLED_WR_Byte(0xdb,OLED_CMD); /*set vcomh*/
OLED_WR_Byte(0x40,OLED_CMD);
OLED_WR_Byte(0x8d,OLED_CMD); /*set charge pump enable*/
OLED_WR_Byte(0x14,OLED_CMD);
OLED_Clear();
OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/
}

5、研究一下传送进去的数据是怎么对应的显示在128*32的点阵上的

图片

如果上图看不懂,就看下面的文字部分。

这个芯片最大支持12864,我手里用的0.91寸的只有12832,也就是只使用PAGE0~PAGE3。

屏幕的点阵横向看作x,即x列,总数是128列,x∈[0,127];

屏幕的点阵竖向看作y,即y行,总数是032行,y∈[0,031];

而芯片写入是按照页写入的,即y属于PAGE0~PAGE3。

所以,这一点很重要。注意,下面这个厂家提供的操作函数种的y是对应的页的编号。

/*
坐标设置,对于128*32分辨率的OLED:x从127;y从0到3
*/


void OLED_Set_Pos(u8 x, u8 y) ;

于是乎显示一个1,我们要把1图像的每一列的8BIT装进一个页的数据里。如下图所示:

图片

这是6*8大小的点阵字符,如果从第一行写,那么就是写入第0页,然后将对应列的几个字节按顺序写入即可。

例如我写入左下角,那么对应的就是PAGE3,然后x坐标对应0,1,2,3,4,5。

OLED_Set_Pos(0,3);
OLED_WR_Byte(0x00,OLED_DATA);
OLED_Set_Pos(1,3);
OLED_WR_Byte(0x00,OLED_DATA);
OLED_Set_Pos(2,3);
OLED_WR_Byte(0x42,OLED_DATA);
OLED_Set_Pos(3,3);
OLED_WR_Byte(0x7F,OLED_DATA);
OLED_Set_Pos(4,3);
OLED_WR_Byte(0x40,OLED_DATA);
OLED_Set_Pos(5,3);
OLED_WR_Byte(0x00,OLED_DATA);

显示效果:

图片

所以,明白了这一点就可以实现各种自定义的图像了。另外,也可以使用相关的生成工具生成相关的图像编码。

比如我们绘制一个电池的图标:

图片

将11个字节数据放到一个数组,这样我们可以用循环调用。

unsigned char temp[11]={0x42,0xFF,0x81,0xBD,0xBD,0xBD,0xBD,0xBD,0x81,0xFF,0x18};

考虑到刚才显示1的那个位置有鼓包,我们将其向右偏移20个像素点放置,同样放在第三页显示。

for(i=0;i< 11;i++)
{
OLED_Set_Pos(i+20,3);
OLED_WR_Byte(temp[i],OLED_DATA);
}
delay_ms(2000);

显示效果如下图所示,怎么样,是不是很赞?现在你是不是学会显示任何图案了?

图片

接下来,我们造一个函数实现一个点的显示,参数为p(x,y)的绝对坐标。

/*
x:0~127;y:0~31
*/


void setPixel(int x, int y)
{
unsigned char page;
unsigned char bits;
page = y / 8;
bits = y % 8;
OLED_Set_Pos(x,page);
OLED_WR_Byte(1<

利用这个函数,我们可以绘制正弦曲线了。

接下来,测试51使用math.h库函数计算正弦波图像,用于显示正弦波。先直接输出一个,然后翻转一个显示。

//正弦波
for(i=0;i< 128;i++)
{
y=16.0+sin(i*3.1415926/32.0)*16.0;
j=(unsigned int)(y);
setPixel(i,j);


}
OLED_Clear();
//正弦波
for(i=0;i< 128;i++)
{
y=16.0-sin(i*3.1415926/32.0)*16.0;
j=(unsigned int)(y);
setPixel(i,j);


}
OLED_Clear();

请注意上面的函数,因为计算过程,正弦函数出来的都是0到1之间的小数,所以要用浮点型,即y为浮点型变量。参与计算的常数也要写作浮点型,免得给优化掉,这样就只能出来一条线了。

同样,如果更改周期参数,即可实现不同周期的正弦波显示。

for(k=8;k<=64;k=k*2)
{
for(i=0;i< 128;i++)
{
y=16.0-sin(i*3.1415926/(float)k)*16.0;
j=(unsigned int)(y);
setPixel(i,j);
}
OLED_Clear();
}
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6034

    文章

    44528

    浏览量

    633605
  • AT89S52
    +关注

    关注

    9

    文章

    358

    浏览量

    87795
  • 函数
    +关注

    关注

    3

    文章

    4317

    浏览量

    62487
  • oled模块
    +关注

    关注

    0

    文章

    4

    浏览量

    2816
收藏 人收藏

    评论

    相关推荐

    单片机很简单,有点电子底子的都可以玩会

    、又可以动手DIY硬件,激发思考,积累的经验更多。误区4,以AT89S52单片机入门AT89S52的内部资源很少,一般的东西都需要外部,而且最小系统必须接晶振和复位电路,很麻烦。可是
    发表于 08-18 15:16

    单片机很简单,有点电子底子的都可以玩会

    建议采用面包板上做实验学习单片机,成本低、又可以动手DIY硬件,激发思考,积累的经验更多。误区4,以AT89S52单片机入门AT89S52
    发表于 06-02 15:16

    【转】单片机入门的方法与误区

    面包板上做实验学习单片机,成本低、又可以动手DIY硬件,激发思考,积累的经验更多。误区4以AT89S52单片机入门AT89S52的内部资源
    发表于 06-21 20:33

    AT89S52单片机的基本特征有哪些

    AT89S52单片机的内部结构是由哪些部分组成的?AT89S52单片机的基本特征有哪些?
    发表于 10-21 08:52

    AT89S52与RS-232的接口电路

    AT89S52与RS-232的接口电路 图5 AT89S52与RS-232的接口电路 单片机采用AT89S52
    发表于 03-07 09:37 3026次阅读
    <b class='flag-5'>AT89S52</b>与RS-232的接口电路

    at89s52单片机引脚图,at89s52引脚说明

    本文为您介绍at89s52单片机引脚图及引脚说明,at89S52特点及其功能。at89S52,高性能的8位单片机
    发表于 04-29 22:04 7.9w次阅读
    <b class='flag-5'>at89s52</b><b class='flag-5'>单片机</b>引脚图,<b class='flag-5'>at89s52</b>引脚说明

    单片机AT89S52实用教程

    本文提供的单片机AT89S52实用教程,希望对你的学习有所帮助!
    发表于 06-03 16:00 794次下载
    <b class='flag-5'>单片机</b><b class='flag-5'>AT89S52</b>实用教程

    AT89S52单片机入门与提高

    发表于 06-02 21:22 190次下载

    AT89S52单片机结构

    AT89S52单片机结构,简单易学,另有相关配套视频教程,请百度云搜索嘿咻大包子
    发表于 05-11 15:26 3次下载

    AT89S52单片机实现数控直流电流源论文

    AT89S52单片机实现数控直流电流源论文
    发表于 05-11 16:55 0次下载

    毕业设计-基于AT89S52单片机的电子万年历设计

    毕业设计-基于AT89S52单片机的电子万年历设计
    发表于 11-03 14:06 84次下载

    单片机AT89S52介绍

    AT89S52单片机的引脚、IO口介绍
    发表于 03-05 14:39 93次下载

    基于AT89S52单片机的蔬菜大棚温湿度检测装置的设计

    基于AT89S52单片机的蔬菜大棚温湿度检测装置的设计
    发表于 04-27 09:38 43次下载

    单片机at89s52和其他单片机比有什么优劣势

    单片机at89s52是一种高性能低功耗的采用CMOS工艺制造的8位微控制器,它提供下列标准特征:8K字节的程序存储器,256字节的RAM,32条I/O线,2个16位定时器/计数器, 一个5中断源两个
    的头像 发表于 05-16 16:52 5.4w次阅读

    AT89S52单片机思维导图

    AT89S52单片机思维导图
    发表于 11-10 18:46 72次下载
    <b class='flag-5'>AT89S52</b><b class='flag-5'>单片机</b>思维导图