stm32+LCD12864+ADC实现将ADC采样的值实时显示

1 篇文章 2 订阅
1 篇文章 0 订阅

前言

这篇文章以上一篇文章为基础,着重讲如何将ADC采样得到的值显示在LCD12864上面,关于如何点亮LCD屏幕,以及实物硬件连线图、原理,请参考之前一篇文章。加上上一篇文章,这算是一个十分迷你的项目了~还有一个比较常用且重要的知识点就是sprintf()函数的使用——在stm32的编程中如何将浮点小数转换成字符串打印。废话不多说,放码吧!

代码

1.lcd.h部分

#ifndef _LCD_H
#define _LCD_H
#include "sys.h"
#include "delay.h"

#define RS PCout(0) //发数据/命令控制口
#define RW PCout(1) //读/写控制口,写比较常用
#define EN PCout(2) //使能口
#define			LINE1		0x80 //第一行起始地址,下同
#define			LINE2 		0x90
#define			LINE3 		0x88
#define			LINE4 		0x98

//以下是点亮你的屏幕必要的六个函数,不能再少了,想添加其他功能就得再加其他函数
void IO_Init(void); //必要的IO口初始化
void CheckBusy(void); //检查忙/闲状态
void LCD_wdat(u8 dat); //写数据
void LCD_wcmd(u8 com); //写命令
void LCD_Init(void); //LCD初始化
void LCD_Wmessage(u8* message,u8 address); //向屏幕里写入字串

#endif


2.lcd.c部分

#include "lcd.h"
#include "sys.h"
#include "delay.h"

u16 temp;

void IO_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);
	
	//想实现控制,激活控制口(PC0,PC1,PC2)必不可少
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOC,&GPIO_InitStructure);
	
	//想发送数据,激活数据口(PA0~PA7)必不可少
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);	
}
//LCD初始化
void LCD_Init()
{
	LCD_wcmd(0x30);//功能设定:基本指令集
	delay_ms(5);
	LCD_wcmd(0x0C);//显示开,关光标
	delay_ms(5);
	LCD_wcmd(0x01);//清除显示
}
//忙判断
void CheckBusy(void)
{
	u8 status;
	RS=0;
	RW=1; //读出数据,RW=1
	GPIOA->ODR = 0xFF;
	do
	{
		EN = 1;
		delay_ms(5);
		status = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_7);//接收BF位,判断是否忙
	}while(status & 0x80);
	EN=0;
}
//LCD写命令
void LCD_wcmd(u8 cmd)
{
	CheckBusy();
	RS=0;
	RW=0;
	delay_ms(5);
	temp=(temp&0xff00)|cmd;//temp的低八位清零后将cmd放进去
	GPIO_Write(GPIOA,temp);//通过GPIO_Write()函数将数据发到A端口(也就是LCD的数据口)
	EN=1;//使能位开启
	delay_ms(10);//10ms应该能发送完了
	EN=0;//使能位关闭
}
//LCD写数据
void LCD_wdat(u8 dat)
{
	CheckBusy();
	RS=1;
	RW=0;
	delay_ms(5);
	temp=(temp&0xff00)|dat; //temp的低八位清零后将dat放进去
	GPIO_Write(GPIOA,temp);//通过GPIO_Write()函数将数据发到A端口(也就是LCD的数据口)
	EN=1;//使能位开启
	delay_ms(10);//10ms应该能发送完了
	EN=0;//使能位关闭
}
//向LCD12864中写入一行数据(因为你不可能每次只发送一字节数据)
void LCD_Wmessage(u8* message,u8 address)
{
	LCD_wcmd(address);//要显示的位置,你想让内容显示在LCD的哪一行,就把该行的起始地址通过写命令的方式发送出去,很神奇,有木有
	while(*message>0)//这个判断很关键,判断你的内容有没有发完
	{
		LCD_wdat(*message); //内核还是发字节函数
		message++; //指针挺好用的。。
	}
}


3.adc.h和lcd.c部分随便参照原子哥的一个ADC例程即可,我也是直接拿过来用的。。采样的是战舰V3板载的光敏电阻
adc.h文件:

#ifndef __ADC_H
#define __ADC_H
#include "sys.h"
#include "stm32f10x.h"
void Adc_Init(void);
u16 Get_Adc(u8 ch);
u16 Get_Adc_Average(u8 ch,u8 times);

#endif

4.adc.c

#include "adc.h"
#include "stm32f10x.h"
#include "delay.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"

void Adc_Init()
{
	ADC_InitTypeDef  ADC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF|RCC_APB2Periph_ADC3, ENABLE );
	//RCC_ADCCLKConfig(RCC_PCLK2_Div6);//12MHZ(不分频好像也没事,现象和分频现象一致。好像有个默认的分频)
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;
	GPIO_Init(GPIOF,&GPIO_InitStructure);
	
	ADC_DeInit(ADC3);  //复位ADC1 
	
	ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;
	ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;
	ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
	ADC_InitStructure.ADC_NbrOfChannel=1;
	ADC_InitStructure.ADC_ScanConvMode=DISABLE;
	ADC_Init(ADC3,&ADC_InitStructure);
	
	ADC_Cmd(ADC3, ENABLE);	//使能指定的ADC3
	ADC_ResetCalibration(ADC3);	//重置指定的ADC3的复位寄存器
	while(ADC_GetResetCalibrationStatus(ADC3));	//获取ADC1重置校准寄存器的状态,设置状态则等待
	ADC_StartCalibration(ADC3);
	while(ADC_GetCalibrationStatus(ADC3));		//获取指定ADC1的校准程序,设置状态则等待

}
u16 Get_Adc(u8 ch)
{
	ADC_RegularChannelConfig(ADC3, ch, 1, ADC_SampleTime_239Cycles5 );
	ADC_SoftwareStartConvCmd(ADC3, ENABLE);		//使能指定的ADC3的软件转换启动功能	
	while(!ADC_GetFlagStatus(ADC3, ADC_FLAG_EOC ));//等待转换结束
	return ADC_GetConversionValue(ADC3);	//返回最近一次ADC3规则组的转换结果
}
u16 Get_Adc_Average(u8 ch,u8 times)
{
	u32 temp_val=0;
	u8 t;
	for(t=0;t<times;t++)
	{
		temp_val+=Get_Adc(ch);
		delay_ms(5);
	}
	temp_val=temp_val/times;
	return temp_val;
}

5.最后就是主函数部分了。前面的代码比较简单,主函数最重要的一个作用就是对接收到的数据进行处理。其中一个就是如何把ADC得到的数字以一个字符串的方式在LCD屏幕上打印出来。这花了我一些时间去找解决方法(因为水平比较烂,所以很多都得找着学~),后来找到了解决方法,就是开头说的sprintf()函数。先把代码发出来:

#include "stm32f10x.h"
#include "sys.h"
#include "lcd.h"
#include "delay.h"
#include "usart.h"
#include "adc.h"

/************************
一行16个字节,一个汉字2字节,一个字母1字节,每个汉字只能在偶字节处起
************************/
int main(void)
{	
	u8 dis1[]={"µ±Ç°µç×èÖµ£º"};
	
	u16 adcx;
	float temp;
	u8 aa[10];
	uart_init(115200);
	Adc_Init();	
	delay_init();
	IO_Init();
	LCD_Init();
	while(1)
	{
		adcx=Get_Adc_Average(ADC_Channel_6,10);
		temp=(float)adcx*(3.3/4096);
		//printf("adcx: %5.3f",temp);//向串口打印验证用
		sprintf(aa,"%5.3f",temp);
		LCD_Wmessage(dis1,LINE1);
		LCD_Wmessage(aa,LINE2+2);
	}
}

可以看到,sprintf()函数一共有三个参数,第一个参数是我们要的(字符串类型),第二个为格式化输出的形式,第三个是待处理的数据(浮点型数据)。因为LCD最终接受的要打印的数据为字符串,所以我们AD采样得到的浮点数据不可以直接发送给LCD_Wmessage()函数,必须经过这样一次处理才能将其打印(一时没想起其他的方法,欢迎有其他方法的伙伴交流进步)。
最后呈现的结果如下:
(没开手电筒时)
在这里插入图片描述
(打开手电筒后)
在这里插入图片描述
完。欢迎大家一起交流,共同进步。
由于时间太久还是有同学来问我要这个工程,而且CSDN自动把这个资源的积分加的太多,所以现在把百度云连接贴出来,大家有需要自行下载(如果你不介意,可以给我点个赞👍哈哈)。
链接:https://pan.baidu.com/s/16Wckkp6pZrIxPoffB1DDyw
提取码:f4m0

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值