【STM32单片机】旋转太空人设计

news2024/11/14 21:04:48

文章目录

  • 一、功能简介
  • 二、软件设计
  • 三、实验现象
  • 联系作者


一、功能简介

本项目使用STM32F103C8T6单片机控制器,使IIC OLED液晶等。
主要功能:
系统运行后,OLED显示动画界面。


二、软件设计

/*
作者:嗨小易(QQ:3443792007)

*/



void IIC_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(OLED_SCL_RCC|OLED_SDA_RCC, ENABLE);	/* 打开GPIO时钟 */
	GPIO_InitStructure.GPIO_Pin = OLED_SCL_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;  	//开漏输出
	GPIO_Init(OLED_SCL_GPIO_PORT, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin = OLED_SDA_PIN;
	GPIO_Init(OLED_SDA_GPIO_PORT, &GPIO_InitStructure);

	//给一个停止信号, 复位IIC总线上的所有设备到待机模式
	IIC_Stop();
}

//初始化SSD1306
void OLED_Init(void)
{
	HZ=GB16_NUM();
	delay_ms(100);
	IIC_GPIO_Config();
	Write_IIC_Command(0xAE); //--display off
	Write_IIC_Command(0x00); //---set low column address
	Write_IIC_Command(0x10); //---set high column address
	Write_IIC_Command(0x40); //--set start line address
	Write_IIC_Command(0xB0); //--set page address
	Write_IIC_Command(0x81); // contract control
	Write_IIC_Command(0xFF); //--128
	Write_IIC_Command(0xA1); //set segment remap
	Write_IIC_Command(0xA6); //--normal / reverse
	Write_IIC_Command(0xA8); //--set multiplex ratio(1 to 64)
	Write_IIC_Command(0x3F); //--1/32 duty
	Write_IIC_Command(0xC8); //Com scan direction
	Write_IIC_Command(0xD3); //-set display offset
	Write_IIC_Command(0x00); //
	Write_IIC_Command(0xD5); //set osc division
	Write_IIC_Command(0x80); //
	Write_IIC_Command(0xD8); //set area color mode off
	Write_IIC_Command(0x05); //
	Write_IIC_Command(0xD9); //Set Pre-Charge Period
	Write_IIC_Command(0xF1); //
	Write_IIC_Command(0xDA); //set com pin configuartion
	Write_IIC_Command(0x12); //
	Write_IIC_Command(0xDB); //set Vcomh
	Write_IIC_Command(0x30); //
	Write_IIC_Command(0x8D); //set charge pump enable
	Write_IIC_Command(0x14); //
	Write_IIC_Command(0xAF); //--turn on oled panel
}

static void IIC_Delay(void)
{
	uint8_t i=3;
	while(i--);
}

/**************************************************
*	函 数 名: IIC_Start
*	功能说明: CPU发起IIC总线启动信号
*	形    参:无
*	返 回 值: 无
***************************************************/
void IIC_Start(void)
{
	/* 当SCL高电平时,SDA出现一个下跳沿表示IIC总线启动信号 */
	OLED_SDA=1;
	OLED_SCL=1;
	IIC_Delay();
	OLED_SDA=0;
	IIC_Delay();
	OLED_SCL=0;
	IIC_Delay();
}

/*************************************************
*	函 数 名: IIC_Stop
*	功能说明: CPU发起IIC总线停止信号
*	形    参:无
*	返 回 值: 无
*************************************************/
void IIC_Stop(void)
{
	/* 当SCL高电平时,SDA出现一个上跳沿表示IIC总线停止信号 */
	OLED_SDA=0;
	OLED_SCL=1;
	IIC_Delay();
	OLED_SDA=1;
}

/***************************************************************************
*	函 数 名: IIC_WaitAck
*	功能说明: CPU产生一个时钟,并读取器件的ACK应答信号
*	形    参:无
*	返 回 值: 返回0表示正确应答,1表示无器件响应
****************************************************************************/
//uint8_t IIC_WaitAck(void)
void IIC_WaitAck(void)
{


	OLED_SDA=1;	/* CPU释放SDA总线 */
	IIC_Delay();
	OLED_SCL=1;	/* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
	IIC_Delay();
	OLED_SCL=0;
	IIC_Delay();
}

//向IIC总线写数据
void Write_IIC_Byte(uint8_t _ucByte)
{
	uint8_t i;

	/* 先发送字节的高位bit7 */
	for (i = 0; i < 8; i++)
	{		
		if (_ucByte & 0x80)
		{
			OLED_SDA=1;
		}
		else
		{
			OLED_SDA=0;
		}
		IIC_Delay();
		OLED_SCL=1;
		IIC_Delay();	
		OLED_SCL=0;
		_ucByte <<= 1;	/* 左移一个bit */
	}
}

//写命令
void Write_IIC_Command(u8 IIC_Command)
{
	IIC_Start();
	Write_IIC_Byte(OLED_ADDRESS);//OLED地址
	IIC_WaitAck();
	Write_IIC_Byte(0x00);//寄存器地址
	IIC_WaitAck();
	Write_IIC_Byte(IIC_Command);
	IIC_WaitAck();
	IIC_Stop();
}

//写数据
void Write_IIC_Data(u8 IIC_Data)
{
	IIC_Start();
	Write_IIC_Byte(OLED_ADDRESS);//OLED地址
	IIC_WaitAck();
	Write_IIC_Byte(0x40);//寄存器地址
	IIC_WaitAck();
	Write_IIC_Byte(IIC_Data);
	IIC_WaitAck();
	IIC_Stop();
}

//将OLED从休眠中唤醒
void OLED_ON(void)
{
	Write_IIC_Command(0X8D);  //设置电荷泵
	Write_IIC_Command(0X14);  //开启电荷泵
	Write_IIC_Command(0XAF);  //OLED唤醒
}

//让OLED休眠 -- 休眠模式下,OLED功耗不到10uA
void OLED_OFF(void)
{
	Write_IIC_Command(0X8D);  //设置电荷泵
	Write_IIC_Command(0X10);  //关闭电荷泵
	Write_IIC_Command(0XAE);  //OLED休眠
}

//OLED全屏填充
void OLED_Fill(u8 fill_Data)
{
	u8 m,n;
	for(m=0;m<8;m++)
	{
		Write_IIC_Command(0xb0+m);		//page0-page1
		Write_IIC_Command(0x00);		//low column start address
		Write_IIC_Command(0x10);		//high column start address
		for(n=0;n<130;n++)
		{
			Write_IIC_Data(fill_Data);
		}
	}
}

//设置起始点坐标
void OLED_Set_Pos(u8 x, u8 y) 
{ 
	Write_IIC_Command(0xb0+y);
	Write_IIC_Command((((x+2)&0xf0)>>4)|0x10);
	Write_IIC_Command(((x+2)&0x0f)|0x01);
}

//更新显存到OLED
void OLED_Refresh(void)
{
	u8 i,n;
	for(i=0;i<8;i++)
	{
		Write_IIC_Command(0xb0+i); //设置行起始地址
		Write_IIC_Command(0x00);   //设置低列起始地址
		Write_IIC_Command(0x10);   //设置高列起始地址
		IIC_Start();
		Write_IIC_Byte(0x78);
		IIC_WaitAck();
		Write_IIC_Byte(0x40);
		IIC_WaitAck();
		for(n=0;n<130;n++)
		{
			Write_IIC_Byte(OLED_GRAM[n][i]);
			IIC_WaitAck();
		}
		IIC_Stop();
	}
}

//清屏
void OLED_Clear(void)
{
	OLED_Fill(0x00);
}


//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
void OLED_ShowChar(u8 x, u8 y, u8 chr)
{
	u8 c = 0, i = 0;
	c = chr - ' '; //得到偏移后的值
	if(x > 130 - 1)
	{
		x = 0;
		y = y + 2;
	}
	OLED_Set_Pos(x, y);
	for(i = 0; i < 8; i++)
		Write_IIC_Data(zf[c * 16 + i]);
	OLED_Set_Pos(x, y + 1);
	for(i = 0; i < 8; i++)
		Write_IIC_Data(zf[c * 16 + i + 8]);
}
//m^n函数
u32 oled_pow(u8 m, u8 n)
{
	u32 result = 1;
	while(n--)result *= m;
	return result;
}
//显示个数字
//x,y :起点坐标
//len :数字的位数
//num:数值(0~4294967295);
//mode:   为1:显示0   为0:显示空格
void OLED_ShowNum(u8 x, u8 y, u32 num, u8 len,u8 mode)
{
	u8 t, temp;
	u8 enshow=0;
	for(t = 0; t < len; t++)
	{
		temp = (num / oled_pow(10, len - t - 1)) % 10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				if(mode)
					OLED_ShowChar(x + 8*t, y, '0');
				else
					OLED_ShowChar(x + 8*t, y, ' ');
				continue;
			}else enshow=1; 		 	 
		}
		OLED_ShowChar(x + 8*t, y, temp + '0');
	}
}

//显示中英文字符
void OLED_ShowCH(u8 x, u8 y,u8 *chs)
{
	u32 i=0;
	u32 j;
	char* m;
	while (*chs != '\0')
	{
		if (*chs > 0xa0)				//汉字内码都是大于0xa0
		{
			for (i=0 ;i < HZ;i++)
			{	
				if(x>112)
				{
					x=0;
					y=y+2;
				}
				if ((*chs == hz_index[i*2]) && (*(chs+1) == hz_index[i*2+1]))
				{
					OLED_Set_Pos(x, y);
					for(j=0;j<16;j++)
						Write_IIC_Data(hz[i*32+j]);
					OLED_Set_Pos(x,y+1);
					for(j=0;j<16;j++)
						Write_IIC_Data(hz[i*32+j+16]);
					x +=16;
					break;
				}
			}
			chs+=2;
		}
		else
		{
			if(x>122)
			{
				x=0;
				y=y+2;
			}
			m=strchr(zf_index,*chs);
			if (m!=NULL)
			{
				OLED_Set_Pos(x, y);
				for(j = 0; j < 8; j++)
					Write_IIC_Data(zf[((u8)*m-' ') * 16 + j]);
				OLED_Set_Pos(x, y + 1);
				for(j = 0; j < 8; j++)
					Write_IIC_Data(zf[((u8)*m-' ') * 16 + j + 8]);
				x += 8;
			}
			chs++;
		}
	}
}


// x0,y0 -- 起始点坐标(x0:0~127, y0:0~7); x1,y1 -- 起点对角线(结束点)的坐标(x1:1~128,y1:1~8)
void OLED_DrawBMP(u8 x0,u8 y0,u8 x1,u8 y1,u8 BMP[])
{
	u16 j=0;
	u8 x,y;

	if(y1%8==0)
		y = y1/8;
	else
		y = y1/8 + 1;
	for(y=y0;y<y1;y++)
	{
		OLED_Set_Pos(x0,y);
		for(x=x0;x<x1;x++)
		{
			Write_IIC_Data(BMP[j++]);
		}
	}
}

//清除最后两行文字
void ShowTrashNoPeople(void)
{
	u8 m,n;				//m起始行数
	for(m=0;m<8;m++)
	{
		Write_IIC_Command(0xb0+m);		//page0-page1
		Write_IIC_Command(0x00);		//low column start address
		Write_IIC_Command(0x10);		//high column start address
		for(n=0;n<130;n++)
		{
			Write_IIC_Data(0x00);
		}
	}
}




三、实验现象

B站演示视频:https://space.bilibili.com/444388619
在这里插入图片描述


联系作者

专注于51单片机、STM32、国产32、DSP、Proteus、ardunio、ESP32、物联网软件开发,PCB设计,视频分享,技术交流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1313045.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Stable Diffusion 系列教程 - 3 模型下载和LORA模型的小白入门

首先&#xff0c;一个比较广泛的模型下载地址为&#xff1a;Civitai Models | Discover Free Stable Diffusion Models 黄框是一些过滤器&#xff0c;比如checkpoints可以理解为比如把1.5版本的SD模型拷贝一份后交叉识别新的画风或场景后得到的模型&#xff0c;可以单独拿出来使…

[CC13X0] XDS100V3连接报错:Make sure your device is unlocked.

用XDS100V3给CC1310下载程序时&#xff0c;发现如下连接错误&#xff1a; An error occurred while hard opening the controller. -----[An error has occurred and this utility has aborted]-------------------- This error is generated by TIs USCIF driver or utilities…

mysql 数据库 关于库的基本操作

库的操作 如果想到 mysql 客户端当中数据 系统当中的命令的话&#xff0c;直接输入的话&#xff0c;会被认为是 mysql 当中的命令。 所以&#xff0c;在mysql 当中执行系统当中的命令的话&#xff0c;要在系统命令之前带上 ststem &#xff0c;表示系统命令&#xff1a; 但是…

[css] flex wrap 九宫格布局

<div class"box"><ul class"box-inner"><li>九宫格1</li><li>九宫格2</li><li>九宫格3</li><li>九宫格4</li><li>九宫格5</li><li>九宫格6</li><li>九宫格7&l…

2024年高效远程协同运维工具推荐

随着企业的不断发展以及变化&#xff0c;企业的内部IT环境也是日益复杂&#xff0c;一跨高效远程协同运维工具必不可少&#xff0c;不仅可以提高生产力&#xff0c;还能降低运营成本。这里就给大家推荐2024年高效远程协同运维工具。 高效远程协同运维工具应用场景 1、IT运维管…

WPF仿网易云搭建笔记(1):项目搭建

文章目录 前言项目地址动态样式组合样式批量样式覆盖Prism新建UserControler修改Material Design 笔刷收放列表可以滚动的StackPanel列表点击展开或折叠 实现效果 前言 今天接着继续细化代码&#xff0c;把整体框架写出来 项目地址 WPF仿网易云 Gitee仓库 动态样式 【WPF】C#…

linux 查看服务启动时间

文章目录 linux 查看服务启动时间参数解析 linux 查看服务启动时间 [root104 ~]# ps -o lstart -p ps -ef |grep -v grep |grep "zookeeper"|awk {print$2}STARTED Fri Dec 15 16:54:10 2023参数解析 linux 命令中 ps -ef 详解 ps -ef表示查看全格式的进程。 ps …

视频号小店需要缴纳保证金吗?保证金缴纳标准,不懂的快来看!

我是电商珠珠 入驻视频号小店&#xff0c;需要缴纳保证金吗&#xff1f;具体缴纳多少&#xff1f;... 这是想要入驻视频号小店的热门话题&#xff0c;今天我就来给大家一一讲明白。 想要入驻视频号小店&#xff0c;就必须要缴纳保证金。保证金是平台为了约束商家的行为&…

LLM之Agent(六)| 使用AutoGen、LangChian、RAG以及函数调用构建超级对话系统

本文我们将尝试AutoGen集成函数调用功能。函数调用最早出现在Open AI API中&#xff0c;它允许用户调用外部API来增强系统的整体功能和效率。例如&#xff0c;在对话过程中根据需要调用天气API。 函数调用和Agent有各种组合&#xff0c;在这里我们将通过函数调用调用RAG检索增强…

Windows 7如何将分区标记为活动分区?

引导分区&#xff0c;也称为引导卷&#xff0c;是包含引导加载程序和Windows操作系统所需文件的磁盘分区&#xff0c;是正常启动计算机的前提。一个正确的引导分区不只要包含相关的可引导数据&#xff0c;还需要将分区标记为活动分区。那么&#xff0c;如何将Windows 7分区标记…

网络安全——基于Snort的入侵检测实验

一、实验目的要求&#xff1a; 二、实验设备与环境&#xff1a; 三、实验原理&#xff1a; 四、实验步骤&#xff1a; 五、实验现象、结果记录及整理&#xff1a; 六、分析讨论与思考题解答&#xff1a; 七、实验截图&#xff1a; 一、实验目的要求&#xff1a; 1、掌握…

SuperMap iPortal权限介绍

作者&#xff1a;yx 文章目录 前言一、内置权限二、自定义权限&#xff08;11.1.0及以后版本&#xff09;1、修改配置文件2、页面展示3、api调用4、结果验证5、实际应用 前言 iPortal 用户访问和使用门户中资源的能力取决于其用户类型与在门户中拥有的权限&#xff0c;权限通过…

深入分析ClassLocader工作机制

文章目录 一、ClassLoader简介1. 概念2. ClassLoader类结构分析 二、ClassLoader的双亲委派机制三、Class文件的加载流程1. 简介2. 加载字节码到内存3. 验证与解析4. 初始化Class对象 四、常见加载类错误分析1. ClassNotFoundException2. NoClassDefFoundError3. UnsatisfiledL…

2023.12.13 关于 MySQL 复杂查询

目录 聚合查询 聚合函数 group by 子句 执行流程图 联合查询 笛卡尔积 内连接 外连接 左外连接 右外连接 自连接 子查询 单行子查询 多行子查询 EXISTS 关键字 合并查询 union on 和 union 的区别 聚合查询 聚合函数 函数说明COUNT([DISTINCT] expr)返回查询到…

wpf TelerikUI使用DragDropManager

首先&#xff0c;我先创建事务对象ApplicationInfo&#xff0c;当暴露出一对属性当例子集合对于构成ListBoxes。这个类在例子中显示如下代码&#xff1a; public class ApplicationInfo { public Double Price { get; set; } public String IconPath { get; set; } public …

【【ZYNQ 7020显示 图片 实验 】】

ZYNQ 7020显示 图片 实验 关键配置 BRAM 因为本次 我想显示的 图片是 400*400 所以在 内部 的 ROM 存储单元选择 了160000 ZYNQ7020的内部资源 最多是 大概 200000左右的 大小 大家可以根据 资源选择合适的像素 此处存放 内部的 图片转文字的COE文件 PLL设置 我选用的是按…

详解wmvcore.dll丢失的解决方法

wmvcore.dll是一款由Microsoft开发的Windows系统文件&#xff0c;主要用于存储和处理多媒体文件&#xff0c;尤其是Windows媒体视频。该文件对于音频和视频的播放至关重要。如果电脑上缺少这个文件&#xff0c;可能会出现播放问题或者相关的应用程序运行错误。在本文中&#xf…

Netty详解

目录标题 1、前期知识科普1.1 NIO 基本概念1.2 java BIO与NIO对比1.3 Reactor 模型 2、Netty 基础概念2.1 Netty 简介2.2 Netty 执行流程2.3 Netty 核心组件 3、Netty Demo编写3.1 总体框架3.2 具体代码 4、交流群 1、前期知识科普 1.1 NIO 基本概念 阻塞&#xff08;Block&a…

0x21 树与图的遍历

0x21 树与图的遍历 树与图最常见的储存方式就是使用一个邻接表保存它们的边集。邻接表以head数组为表头&#xff0c;使用ver和edge数组分别存储边的终点和权值&#xff0c;使用next数组模拟链表指针&#xff08;就像我们在0x13节中讲解邻接表所给出的代码那样&#xff09;。 …

科技铸就企业转型钢筋铁骨,群硕获评2023年度数字化影响力企业

12月15日&#xff0c;STIF2023第四届国际科创节暨DSC2023国际数字服务大会在北京顺利举行&#xff0c;本次大会以“数实融合 推动高质量发展”为主题&#xff0c;各大科技服务企业齐聚一堂&#xff0c;共同探讨2023科技发展新趋势。 大会上&#xff0c;群硕软件继2022年后再度…