基于STM32波形信号发生器proteus仿真设计(仿真+程序+报告+讲解)

news2024/11/15 11:54:26

基于STM32波形信号发生器proteus仿真设计(仿真+程序+报告+讲解)

仿真图proteus 8.9

程序编译器:keil 5

编程语言:C语言

设计编号:C0075

讲解仿真视频:

基于STM32的波形信号发生器proteus仿真设计

主要功能:

结合实际情况,基于STM32F103单片机设计一个四种波形发生器(正弦波、方波、三角波、锯齿波)。该系统应满足的功能要求为:

(1) 可以实现四种波形:正弦波、方波、三角波、锯齿波;

(2) 通过按键进行选择,频率可以调整;

(3) LCD液晶显示;

(4)设计出来之后用Proteus软件仿真出效果;

主要硬件设备:STM32F103单片机、DAC0832数模转换芯片、矩阵键盘、LCD12864液晶屏幕。

资料下载链接(可点击):

【腾讯文档】C0075 下载链接

以下为本设计资料展示图:

整体设计方案

四种波形发生器以STM32F103单片机作为整个系统的控制核心,应用其强大的处理速度,构成波形发生器系统。该系统具备将数字信号转换为模拟信号的能力。正弦波可以直接采用数学函数sin计算出来,送入单片机进行数据处理。经单片机运算后的数据送入DAC0832芯片将数字信号转换为模拟信号输出。其他的波形都可以采用自身的规律采用不同的算法实现。

img

图2-1 基于STM32单片机的四种波形发生器原理图

本系统硬件主要由矩阵键盘、D/A转换器、LCD12864显示系统、处理器等几部分组成。各模块的主要功能如下:

(1)矩阵键盘的功能是设置波形和频率,然后送入单片机。

(2) MCU的功能是识别键盘的数据并进行相对应的处理,然后转换出波形的数字信号和LCD显示的数据。

(3) LCD12864显示系统的功能是将设置的波形和频率显示出来。

系统的整体设计方案设计图如图2-2所示。

img

图2-2 系统的整体方案设计图

采用的是DAC0832芯片来做DA转换的,DAC0832将输出电压分成了0xFF(255)份,需要输出不同的波形我们需要给不同的数据,在这里我将所有的波形的一个周期分成了100份,定时器每隔一段时间中断一次,中断100次为一个周期。

正弦波采用数学计算公式sin来计算;

方波只需要在定时器前面50次给0,后面50次给最大值即可;

三角波只需要在定时器前面50次采用最大值的50分之一乘于它本身,后面50次相反即可;

锯齿波只需要在一个周期内,定时器中断一次就用他本身乘于电压最大值的100分之一即可;

测试波形如下所示:

三角波

img

锯齿波

img

方波

img

正弦波

img

程序:

img

img

main函数

#define KEY0  GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)		//读取按键0

void Delay_Ms(u16 time);

 /***************  配置Switch用到的I/O口 *******************/
void Init_GPIO_Switch(void)	
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//关闭jtag,使能SWD,可以用SWD模式调试
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);	// 使能PC端口时钟 
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_10;				//PC0 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		//IO口速度为50MHz
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 	//设置成输入
 	GPIO_Init(GPIOB, &GPIO_InitStructure);					//初始化PC0
}

/* Private functions ---------------------------------------------------------*/ 
/*******************************************************************************
*功能名称:main
*描述:主程序。
*输入:无
*输出:无
*返回:无
*******************************************************************************/
int main(void)
{
	u8 i=0;
	RCC_ClocksTypeDef RCC_Clocks;		//初始化程序
	
	RCC_Configuration(RCC_PLLMul_4);	//8M*4 == 32M
	RCC_GetClocksFreq(&RCC_Clocks);		//获取片上时钟
	
    Init_12864();      				 	//初始化12864液晶
	
	Key_Init();  				
	Init_GPIO_Switch();
	Init_GPIO_DAC0832();
	
	Data0=25;
	TIM3_Int_Init(50+Data0,320);	//频率:32000000/ 320 ==100 000	/100 == 1000 /50==20
	
	LCD_P6x8Str(3,16,"   Sine Wave   ");
	LCD_P6x8Str(7,6*2,"Frequency: 15 Hz");
	
  	while (1)
  	{
		if(KEY0)
		{
			if(i!=2)
			{
				__set_PRIMASK(1);
				GPIO_ResetBits(GPIOB, ((uint16_t)0xC000));
			}
			Key_Test();	
			
			i=2;
		}
		else{
			
			if(i!=5)
			{
				TIM3_Int_Init(50+Data0,320);
				__set_PRIMASK(0);  				//使能TIMx外设
				GPIO_ResetBits(GPIOB, ((uint16_t)0xC000));
			}
			
			i=5;
		}	
  	}
}

波形信号部分

 /***************  配置DAC用到的I/O口 *******************/
void Init_GPIO_DAC0832(void)	
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);	// 使能PC端口时钟  
	GPIO_InitStructure.GPIO_Pin = ((uint16_t)0x03FF);		//选择对应的引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		//IO口速度为50MHz
	GPIO_Init(GPIOC, &GPIO_InitStructure);					//初始化PC端口
	GPIO_SetBits(GPIOC, ((uint16_t)0x00FF));				// 高
	GPIO_ResetBits(GPIOC, ((uint16_t)0x00FF));				// 低
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);	// 使能PC端口时钟  
	GPIO_InitStructure.GPIO_Pin = ((uint16_t)0xC000);		//选择对应的引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		//IO口速度为50MHz
	GPIO_Init(GPIOB, &GPIO_InitStructure);					//初始化PC端口
	GPIO_SetBits(GPIOC, ((uint16_t)0xC000));				// 高
	GPIO_ResetBits(GPIOC, ((uint16_t)0xC000));				// 低
	
	
	time=0;
	ADC_CS_WR(0);
	mode=0;		//默认输出正弦波
	freq=100;	//默认频率
	AM=255;		//最大幅度
}

void DAC_0832_Data(uint8_t Data)
{
	GPIO_ResetBits(GPIOC,~Data);
	GPIO_SetBits(GPIOC,Data);
}

void sine_wave(u8 location)//输出正弦波
{
	double x=(double)location/50*PI;//把0-100放缩到0-2派(pai,没有那个符号)
	u8 y=(sin(x)*(AM/2)+(AM/2));//算出y,并放缩到0-254(因为ADC范围0-AM,芯片落后)
	DAC_0832_Data(y);
}

void squ_wave(u8 location)//方……
{
	if(location<50)
		DAC_0832_Data(AM);
	else
		DAC_0832_Data(0);//这个简单
}

void tri_wave(u8 location)//三……
{
	//为了简化,在单周期输出V字形
	u8 y;
	if(location<50)
		y=(50-location)*AM/50;
	else
		y=(location-50)*AM/50;
	DAC_0832_Data(y);
	//偶函数,当然说奇函数也没错
	
}

void saw_wave(u8 location)//锯……
{
	DAC_0832_Data(location*AM/100);
	//用(100-location)也以变成反向锯齿
}

//通用定时器中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能

	TIM_TimeBaseStructure.TIM_Period = arr; 			//设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 计数到5000为500ms
	TIM_TimeBaseStructure.TIM_Prescaler =psc; 			//设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; 		//设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 	//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(  //使能或者失能指定的TIM中断
		TIM3, 		//TIM3
		TIM_IT_Update ,
		ENABLE  	//使能
		);
//	TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 	//IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);  				//根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

	TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设
//	TIM_Cmd(TIM3, DISABLE);	
}

void TIM3_IRQHandler(void)   //TIM3中断
{
	switch(mode)
	{
		case W_SINE:sine_wave((u8)(time*freq/100)%100);break;//计算出波的位置
		case W_SQU:squ_wave((u8)((time*freq/100)%100));break;
		case W_TRI:tri_wave((u8)((time*freq/100)%100));break;
		case W_SAW:saw_wave((u8)((time*freq/100)%100));break;
	}
	time++;
	if(time>=100)//计数100次
		time=0;
}

按键识别

/************************************
        按键表盘为:			1  2  3  A 
							4  5  6  B
							7  8  9  C
							*  0  #  D 
************************************/

u8 ee,Data0=0;
void Key_Test(void) 
{
    int num;
	char Freq[3]={'\0'};
	  num = Key_Scan();
	if(ee!=num)
	  switch(num)
	  { 
			case 0: LCD_P6x8Str(1,1,"0"); break;
			case 1: LCD_P6x8Str(1,1,"1"); break;
			case 2: LCD_P6x8Str(1,1,"2"); break;
			case 3: LCD_P6x8Str(1,1,"3"); break;
			case 4: LCD_P6x8Str(1,1,"4"); break;
			case 5: LCD_P6x8Str(1,1,"5"); break;
			case 6: LCD_P6x8Str(1,1,"6"); break;
			case 7: LCD_P6x8Str(1,1,"7"); break;
			case 8: LCD_P6x8Str(1,1,"8"); break;
			case 9: LCD_P6x8Str(1,1,"9"); break;//
			case 'A': LCD_P6x8Str(1,1,"A");  mode=0;LCD_P6x8Str(3,16,"   Sine Wave   "); break;
			case 'B': LCD_P6x8Str(1,1,"B");  mode=1;LCD_P6x8Str(3,16,"  Square wave  "); break;
			case 'C': LCD_P6x8Str(1,1,"C");  mode=2;LCD_P6x8Str(3,16,"Ttiangular wave"); break;
			case 'D': LCD_P6x8Str(1,1,"D");  mode=3;LCD_P6x8Str(3,16," Sawtooth Wave "); break;
			case '#': LCD_P6x8Str(1,1,"#"); if(Data0>=5)Data0-=5; Freq[0]=(20-Data0/5)/10+'0';Freq[1]=(20-Data0/5)%10+'0'; LCD_P6x8Str(7,6*13,Freq); break;
			case '*': LCD_P6x8Str(1,1,"*"); if(Data0<50)Data0+=5; Freq[0]=(20-Data0/5)/10+'0';Freq[1]=(20-Data0/5)%10+'0'; LCD_P6x8Str(7,6*13,Freq); break;
      }
	  ee=num;
}

资料清单:

下载链接见文章最开头
资料清单

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

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

相关文章

nessus无法导出报告(nessus转中文报告)

nessus漏扫报告&#xff0c;可是nessus导出的报告全是英文&#xff0c;客户说看不懂(说的好像中文就能看懂似的)。找了很多nessus转中文报告的工具都不是很靠谱&#xff0c;今天突然灵机一动发现了一个解决nessus无法导出报告方法。总的说来就是生产一个html文件转中文。 ness…

入门系列 - Git安装与配置

Git安装与配置 要使用Git&#xff0c;你必须在你的电脑上安装它。要不要使用并升级到最新的Git&#xff0c;那取决您的需要了。 下载Git 要下载Git安装程序&#xff0c;请访问Git的官方网站并进入下载页面。本文写于2022-11-29&#xff0c;此时您可以去官网链接去下载&#…

AI教你学测试

ChatGPT这个词相信大家最近看到都不会陌生&#xff0c;应该刷爆了各位的朋友圈&#xff0c;各种分享注册教程、什么AI写代码的文章比比皆是&#xff0c;今天&#xff0c;让我们一起来看一下OpenAI能不能教我们学测试呢&#xff0c;对测试人员的日常工作是否有帮助呢&#xff1f…

原生API编写简单富文本编辑器004

原生API编写富文本编辑器004 遗留的问题&#xff1a; 设置的字体是使用 font属性&#xff0c;而非CSS设置的字号只接受1-7, 并且是以 size 属性而非 CSS控制&#xff0c;超出大小无法设置。color使用HTML的input时&#xff0c;始终有一个input框在那里&#xff0c;并且如果手…

Oracle项目业务表单设计:Oracle PrimaveraUnifier BP

目录 基本介绍 Basic Introduction 业务流程组件 Business Process Components 数据定义 Data Definitions 数据要素 Data Elements 状态 Status 表单 Forms 工作流程 &#xff08;可选&#xff09;Workflow 日志 Log 上部表单 Upper Form 详细表单 Detail Form 行项…

找不到msvcr110dll,无法继续执行代码,解决方法分享

找不到msvcr110dll,无法继续执行代码&#xff0c;电脑出现这种情况&#xff0c;主要是缺失了msvcr110dll这个文件。 要解决这个问题&#xff0c;其实不难&#xff0c;有多种方法 第一种解决msvcr110dll的方法 1在百度搜索下载msvcr110.dll文件 2下载后将文件放在c盘windows…

Stimulsoft Dashboards.PHP 2022.4.5 Crack

Stimulsoft Dashboards.PHP 是一个用于设计和查看仪表板的完整软件包。您可以使用该工具集成到您的应用程序中或作为独立的解决方案。同时&#xff0c;不需要复杂的配置或第三方模块。您可以轻松地将仪表板集成到几乎任何 PHP 应用程序中。 仪表板设计器是一个直接影响分析面板…

【推荐学习收藏】9种回归算法及实例总结的太详细了

我相信很多人跟我一样&#xff0c;学习机器学习和数据科学的第一个算法是线性回归&#xff0c;它简单易懂。由于其功能有限&#xff0c;它不太可能成为工作中的最佳选择。大多数情况下&#xff0c;线性回归被用作基线模型来评估和比较研究中的新方法。 在处理实际问题时&#…

Web大学生网页作业成品——游戏主题HTM5网页设计作业成品 (HTML+CSS王者荣耀8页)

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

043-推箱子游戏源代码3

上一讲:042-推箱子游戏源代码2 摘要: 1、使用JAVA基础知识 2、GUI界面编程实现推箱子界面,常用控件的综合应用; 3、使用JAVA绘图技术实现推箱子过程的绘图功能; 4、使用键盘事件,通过方向键实现推箱子过程; 5、使用音频技术,实现播放背景音乐功能; 6、使用IO流技…

从西北工业大学被攻击说起,谈网络安全的最后一道防线—密码

一、背景 据央视2022年9月5日报道&#xff0c;我国西北工业大学&#xff08;以下简称西工大&#xff09;遭到美国国家情报局特定入侵办公室&#xff08;代号TAO&#xff09;非法入侵&#xff0c;目前已查明涉案人员13人&#xff0c;攻击次数一千余次&#xff0c;大量关键核心数…

保姆级微信双开教程

不知道大家是不是和我一样&#xff0c;两个微信账号&#xff0c;一个用于工作&#xff0c;一个用于私人。 一般来说&#xff0c;日常生活中使用的登录微信的设备也就3种&#xff0c;PC、Android、IOS。这三种设备中&#xff0c;Android经过各种厂商对OS的优化后&#xff0c;基本…

动态规划入门-01背包问题

动态规划入门-01背包问题 问题描述 假设你有个最大载重量为300kg300kg300kg的背包&#xff0c;有4个物品。它们的重量分别为123kg,88kg,93kg,100kg123kg,88kg,93kg,100kg123kg,88kg,93kg,100kg&#xff0c;价值分别为$$10,$19,$8,$20$。 请问背包内最大可以放入多少价值的物品…

第二证券|ChatGPT被“玩坏”,美图大涨45%,AIGC赛道风口来了?

AIGC&#xff08;人工智能主动生成内容&#xff09;近期被ChatGPT带火了&#xff01; 近来明星人工智能公司OpenAI发布了全新的谈天机器人模型ChatGPT。该模型能够主动生成代码以及绘画、答复一系列问题、承认自己的错误、质疑不正确的假设&#xff0c;乃至回绝不合理的要求&a…

Caspase-1活性分析:艾美捷FAM-FLICA试剂盒解决方案

艾美捷FAM-FLICA Caspase-1 (YVAD) Assay Kit FAM-FLICA Caspase-1 活性分析试剂盒检测方案&#xff1a; 1、凋亡诱导&#xff1a; 在开始实验之前&#xff0c;确定可重复的方法用于通过触发胱天蛋白酶活性获得阳性对照。此过程随每个细胞系而显著变化。例如&#xff0c;细胞…

JUC并发编程第九篇,原子操作类分类解析,LongAdder为什么这么快原理分析?

JUC并发编程第九篇&#xff0c;原子操作类分类解析&#xff0c;LongAdder为什么这么快原理分析&#xff1f;一、基本类型原子类二、数组类型原子类三、引用类型原子类四、对象的属性修改原子类五、原子操作增强类六、原理分析&#xff0c;LongAdder 为什么这么快&#xff1f;位…

JS获取音频的总时长,解决Audio元素duration为NaN || Infinity 问题

当我们在加载一个线上mp3地址或者获取audio的duration的时候&#xff0c;会发现有拿到duration是Infinity的情况&#xff0c;这时如果我们动态的展示录音时间时候就会有问题。首先明确一下这是chrome浏览器自己的存在的一个bug&#xff0c;因为我们拿到的录音数据流没有定义长度…

商务与经济统计 | 推断统计

一.概率 事件 若干样本点的集合 事件的概率 等于事件中所有的样本点概率之和 条件概率 贝叶斯定理 二.离散型概率分布 随机变量 是一次试验的结果的数值性描述 离散型随机变量 指的是有穷个数值或一系列无穷的数值的随机变量 连续型随机变量 代表某一区间或多个区间…

通配符的应用

我们使用通配符描述切入点&#xff0c;主要的目的就是简化之前的配置&#xff0c;具体都有哪些通配符可以使用? *:单个独立的任意符号&#xff0c;可以独立出现&#xff0c;也可以作为前缀或者后缀的匹配符出现 execution&#xff08;public * com.itheima.*.UserService.find…

webpack基础配置教程

文章目录1.初识Webpack2.开启项目3.处理js和json文件webpack小试牛刀webpack打包js/json文件webpack默认不能处理css4.webpack配置文件1.初识Webpack 什么是webpack? Webpack是一个模块打包器&#xff08;意思同构建工具&#xff0c;所谓构建︰将程序员写完的【源代码】&#…