大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
前言
刚开始学习STM32,用的是开发板是野火的指南者,这款板子网上资源很多。在学习ADC和LCD部分时,想利用手头仅有的LCD1602A进行显示电压,借助原有例程,经过不断调试后,就有如下代码(仅做交流学习)。
代码
main.c
#include "stm32f10x.h"
#include "bsp_SysTick.h"
#include "bsp_lcd1602a.h"
#include "bsp_adc.h"
#include <stdio.h>
extern __IO uint16_t ADC_ConvertedValue;
// 局部变量,用于保存转换计算后的电压值
float ADC_ConvertedValueLocal;
int main(void)
{
uint8_t a[10];
USART_Config();
// ADC 初始化
ADCx_Init();
/*LCD1602A初始化*/
Lcd_Init();
Lcd1602a_ClearScreen();
Lcd1602a_Disp_Strs(0, 0, "voltage=");
Lcd1602a_Disp_Strs(14, 1, "V");
while(1)
{
ADC_ConvertedValueLocal =(float) ADC_ConvertedValue/4096*3.3;
sprintf(a,"%5.3f",ADC_ConvertedValueLocal);
Lcd1602a_Disp_Strs(7, 1, a);
SysTick_Delay_Ms(1000); //一秒刷新一次
}
这里的参数可以根据自己意愿调整字符显示位置,不过LCD1602A只有两行。这里运用了sprintf函数,这个函数可以将ADC获取的数据转化为字符串,具体用法可自行百度。
bsp_adc.h
#ifndef __ADC_H
#define __ADC_H
#include "stm32f10x.h"
// ADC 编号选择
// 可以是 ADC1/2,如果使用ADC3,中断相关的要改成ADC3的
#define ADC_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ADCx ADC2
#define ADC_CLK RCC_APB2Periph_ADC2
// ADC GPIO宏定义
// 注意:用作ADC采集的IO必须没有复用,否则采集电压会有影响
#define ADC_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ADC_GPIO_CLK RCC_APB2Periph_GPIOC
#define ADC_PORT GPIOC
#define ADC_PIN GPIO_Pin_1
// ADC 通道宏定义
#define ADC_CHANNEL ADC_Channel_11
void ADCx_Init(void);
#endif /* __ADC_H */
这里的ADC通道和引脚可以根据数据手册进行自定义更改。
bsp_adc.c
#include "bsp_adc.h"
__IO uint16_t ADC_ConvertedValue;
//ADC GPIO初始化
static void ADCx_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 打开 ADC IO端口时钟
ADC_GPIO_APBxClock_FUN ( ADC_GPIO_CLK, ENABLE );
// 配置 ADC IO 引脚模式
// 必须为模拟输入
GPIO_InitStructure.GPIO_Pin = ADC_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
// 初始化 ADC IO
GPIO_Init(ADC_PORT, &GPIO_InitStructure);
}
//配置ADC工作模式
static void ADCx_Mode_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
// 打开ADC时钟
ADC_APBxClock_FUN ( ADC_CLK, ENABLE );
// ADC 模式配置
// 只使用一个ADC,属于独立模式
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
// 禁止扫描模式,多通道才要,单通道不需要
ADC_InitStructure.ADC_ScanConvMode = DISABLE ;
// 连续转换模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
// 不用外部触发转换,软件开启即可
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
// 转换结果右对齐
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
// 转换通道1个
ADC_InitStructure.ADC_NbrOfChannel = 1;
// 初始化ADC
ADC_Init(ADCx, &ADC_InitStructure);
// 配置ADC时钟为PCLK2的8分频,即9MHz
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
// 配置 ADC 通道转换顺序和采样时间
ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1,
ADC_SampleTime_55Cycles5);
// ADC 转换结束产生中断,在中断服务程序中读取转换值
ADC_ITConfig(ADCx, ADC_IT_EOC, ENABLE);
// 开启ADC ,并开始转换
ADC_Cmd(ADCx, ENABLE);
// 初始化ADC 校准寄存器
ADC_ResetCalibration(ADCx);
// 等待校准寄存器初始化完成
while(ADC_GetResetCalibrationStatus(ADCx));
// ADC开始校准
ADC_StartCalibration(ADCx);
// 等待校准完成
while(ADC_GetCalibrationStatus(ADCx));
// 由于没有采用外部触发,所以使用软件触发ADC转换
ADC_SoftwareStartConvCmd(ADCx, ENABLE);
}
static void ADC_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
// 优先级分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
// 配置中断优先级
NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void ADCx_Init(void)
{
ADCx_GPIO_Config();
ADCx_Mode_Config();
ADC_NVIC_Config();
}
bsp_lcd1602a.h
#ifndef __BSP_LCD1602A_H
#define __BSP_LCD1602A_H
#include "stm32f10x.h"
#include "bsp_SysTick.h"
//以下引脚根据开发板的引脚自行设置好:1.时钟 2.GPIOx 3.引脚号
//RS --> data/cmd select io
#define LCD1602A_RS_CLK RCC_APB2Periph_GPIOB
#define LCD1602A_RS_PORT GPIOB
#define LCD1602A_RS_PIN GPIO_Pin_5
//R/W --> write/read select io
#define LCD1602A_RW_CLK RCC_APB2Periph_GPIOB
#define LCD1602A_RW_PORT GPIOB
#define LCD1602A_RW_PIN GPIO_Pin_6
//E --> en flag
#define LCD1602A_E_CLK RCC_APB2Periph_GPIOB
#define LCD1602A_E_PORT GPIOB
#define LCD1602A_E_PIN GPIO_Pin_7
/********8'bit data line***************/
//D0
#define LCD1602A_D0_CLK RCC_APB2Periph_GPIOB
#define LCD1602A_D0_PORT GPIOB
#define LCD1602A_D0_PIN GPIO_Pin_0
//D1
#define LCD1602A_D1_CLK RCC_APB2Periph_GPIOC
#define LCD1602A_D1_PORT GPIOC
#define LCD1602A_D1_PIN GPIO_Pin_13
//D2
#define LCD1602A_D2_CLK RCC_APB2Periph_GPIOE
#define LCD1602A_D2_PORT GPIOE
#define LCD1602A_D2_PIN GPIO_Pin_5
//D3
#define LCD1602A_D3_CLK RCC_APB2Periph_GPIOA
#define LCD1602A_D3_PORT GPIOA
#define LCD1602A_D3_PIN GPIO_Pin_6
//D4
#define LCD1602A_D4_CLK RCC_APB2Periph_GPIOA
#define LCD1602A_D4_PORT GPIOA
#define LCD1602A_D4_PIN GPIO_Pin_4
//D5
#define LCD1602A_D5_CLK RCC_APB2Periph_GPIOB
#define LCD1602A_D5_PORT GPIOB
#define LCD1602A_D5_PIN GPIO_Pin_1
//D6
#define LCD1602A_D6_CLK RCC_APB2Periph_GPIOB
#define LCD1602A_D6_PORT GPIOB
#define LCD1602A_D6_PIN GPIO_Pin_8
//D7
#define LCD1602A_D7_CLK RCC_APB2Periph_GPIOC
#define LCD1602A_D7_PORT GPIOC
#define LCD1602A_D7_PIN GPIO_Pin_6
//SETTING BIT AND STATS
#define LCD1602A_RS_SET GPIO_SetBits(LCD1602A_RS_PORT, LCD1602A_RS_PIN)
#define LCD1602A_RS_CLR GPIO_ResetBits(LCD1602A_RS_PORT, LCD1602A_RS_PIN)
#define LCD1602A_RW_SET GPIO_SetBits(LCD1602A_RW_PORT, LCD1602A_RW_PIN)
#define LCD1602A_RW_CLR GPIO_ResetBits(LCD1602A_RW_PORT, LCD1602A_RW_PIN)
#define LCD1602A_E_SET GPIO_SetBits(LCD1602A_E_PORT, LCD1602A_E_PIN)
#define LCD1602A_E_CLR GPIO_ResetBits(LCD1602A_E_PORT, LCD1602A_E_PIN)
/*all_define*/
#define LCD1602A_CMD_LINE_CLK LCD1602A_RS_CLK | LCD1602A_RW_CLK | LCD1602A_E_CLK
#define LCD1602A_DATA_LINE_CLK LCD1602A_D0_CLK | LCD1602A_D1_CLK | LCD1602A_D2_CLK \
| LCD1602A_D3_CLK | LCD1602A_D4_CLK | LCD1602A_D5_CLK \
| LCD1602A_D6_CLK | LCD1602A_D7_CLK
/*sel_write_operation_mode*/
typedef enum {
Com = 0, Data = !Com} SelectStatus;
#define MODE_GPIO GPIO_Mode_Out_PP
/*function mode*/
void Lcd_Write_State(SelectStatus Com_or_Data, uint8_t Write_Data);
void BSP_GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, SelectStatus BitVal);
void BSP_GPIO_Write(uint8_t Data);
void Lcd_Write_State(SelectStatus Com_or_Data, uint8_t Write_Data);
void Lcd_Init(void);
void Lcd1602a_ClearScreen(void);
void Lcd1602a_Set_Cursor(uint8_t x, uint8_t y);
void Lcd1602a_Disp_One_Str(uint8_t x, uint8_t y, uint8_t Str);
void Lcd1602a_Disp_Strs(uint8_t x, uint8_t y, uint8_t *Str);
#endif /*__BSP_LCD1602A_H*/
bsp_lcd1602a.c
#include "bsp_lcd1602a.h"
static void Lcd_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*cmd_line*/
RCC_APB2PeriphClockCmd(LCD1602A_CMD_LINE_CLK, ENABLE);
GPIO_InitStructure.GPIO_Mode = MODE_GPIO;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = LCD1602A_RS_PIN; /*RS*/
GPIO_Init(LCD1602A_RS_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LCD1602A_RW_PIN; /*RW*/
GPIO_Init(LCD1602A_RS_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LCD1602A_E_PIN; /*E*/
GPIO_Init(LCD1602A_E_PORT, &GPIO_InitStructure);
/*data_line*/
RCC_APB2PeriphClockCmd(LCD1602A_DATA_LINE_CLK, ENABLE);
GPIO_InitStructure.GPIO_Mode = MODE_GPIO;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = LCD1602A_D0_PIN; /*D0*/
GPIO_Init(LCD1602A_D0_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LCD1602A_D1_PIN; /*D1*/
GPIO_Init(LCD1602A_D1_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LCD1602A_D2_PIN; /*D2*/
GPIO_Init(LCD1602A_D2_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LCD1602A_D3_PIN; /*D3*/
GPIO_Init(LCD1602A_D3_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LCD1602A_D4_PIN; /*D4*/
GPIO_Init(LCD1602A_D4_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LCD1602A_D5_PIN; /*D5*/
GPIO_Init(LCD1602A_D5_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LCD1602A_D6_PIN; /*D6*/
GPIO_Init(LCD1602A_D6_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LCD1602A_D7_PIN; /*D7*/
GPIO_Init(LCD1602A_D7_PORT, &GPIO_InitStructure);
}
void BSP_GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, SelectStatus BitVal)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GET_GPIO_PIN(GPIO_Pin));
assert_param(IS_GPIO_BIT_ACTION(BitVal));
if (BitVal != Bit_RESET)
{
GPIOx->BSRR = GPIO_Pin;
}
else
{
GPIOx->BRR = GPIO_Pin;
}
}
void BSP_GPIO_Write(uint8_t Data)
{
/*D0*/
if(((Data&0x01)>>0) == 0x01)
{
LCD1602A_D0_PORT->BSRR = LCD1602A_D0_PIN;
}
else
{
LCD1602A_D0_PORT->BRR = LCD1602A_D0_PIN;
}
/*D1*/
if(((Data&0x02)>>1) == 0x01)
{
LCD1602A_D1_PORT->BSRR = LCD1602A_D1_PIN;
}
else
{
LCD1602A_D1_PORT->BRR = LCD1602A_D1_PIN;
}
/*D2*/
if(((Data&0x04)>>2) == 0x01)
{
LCD1602A_D2_PORT->BSRR = LCD1602A_D2_PIN;
}
else
{
LCD1602A_D2_PORT->BRR = LCD1602A_D2_PIN;
}
/*D3*/
if(((Data&0x08)>>3) == 0x01)
{
LCD1602A_D3_PORT->BSRR = LCD1602A_D3_PIN;
}
else
{
LCD1602A_D3_PORT->BRR = LCD1602A_D3_PIN;
}
/*D4*/
if(((Data&0x10)>>4) == 0x01)
{
LCD1602A_D4_PORT->BSRR = LCD1602A_D4_PIN;
}
else
{
LCD1602A_D4_PORT->BRR = LCD1602A_D4_PIN;
}
/*D5*/
if(((Data&0x20)>>5) == 0x01)
{
LCD1602A_D5_PORT->BSRR = LCD1602A_D5_PIN;
}
else
{
LCD1602A_D5_PORT->BRR = LCD1602A_D5_PIN;
}
/*D6*/
if(((Data&0x40)>>6) == 0x01)
{
LCD1602A_D6_PORT->BSRR = LCD1602A_D6_PIN;
}
else
{
LCD1602A_D6_PORT->BRR = LCD1602A_D6_PIN;
}
/*D7*/
if(((Data&0x80)>>7) == 0x01)
{
LCD1602A_D7_PORT->BSRR = LCD1602A_D7_PIN;
}
else
{
LCD1602A_D7_PORT->BRR = LCD1602A_D7_PIN;
}
}
void Lcd_Write_State(SelectStatus Com_or_Data, uint8_t Write_Data)
{
LCD1602A_E_CLR;
SysTick_Delay_Ms( 1);
LCD1602A_RW_CLR;
BSP_GPIO_WriteBit(LCD1602A_RS_PORT, LCD1602A_RS_PIN, Com_or_Data);
BSP_GPIO_Write(Write_Data);
SysTick_Delay_Ms( 1);/*MIN-30ns*/
LCD1602A_E_SET;
SysTick_Delay_Ms( 2);/*MIN-150ns*/
LCD1602A_E_CLR;
SysTick_Delay_Ms( 3);
}
static void Lcd_Config(void)
{
SysTick_Delay_Ms( 150);
Lcd_Write_State(Com, 0x38);
SysTick_Delay_Ms( 3);
Lcd_Write_State(Com, 0x38);
SysTick_Delay_Ms( 3);
Lcd_Write_State(Com, 0x38);
SysTick_Delay_Ms( 3);
Lcd_Write_State(Com, 0x38);
SysTick_Delay_Ms( 3);
Lcd_Write_State(Com, 0x08);/**显示关闭**/
SysTick_Delay_Ms( 3);
Lcd_Write_State(Com, 0x01);/*清屏*/
SysTick_Delay_Ms( 3);
Lcd_Write_State(Com, 0x0f);/*显示开,光标开,光标闪烁开*/
SysTick_Delay_Ms( 3);
Lcd_Write_State(Com, 0x06);/*地址自增一,屏幕不移动*/
}
void Lcd_Init(void)
{
Lcd_GPIO_Config();
Lcd_Config();
}
/*清屏*/
void Lcd1602a_ClearScreen(void)
{
Lcd_Write_State(Com, 0x01);
}
/*设置光标位置*/
void Lcd1602a_Set_Cursor(uint8_t x, uint8_t y)
{
if (y == 0)
{
Lcd_Write_State(Com, 0x80 + x);//第一行
}
else
{
Lcd_Write_State(Com, 0xC0 + x);//第二行
}
}
/*显示字符串,坐标(x,y),str 字符串指针*/
void Lcd1602a_Disp_Strs(uint8_t x, uint8_t y, uint8_t *Str)
{
if (y == 0)
{
Lcd_Write_State(Com, 0x80 + x);
}
else
{
Lcd_Write_State(Com, 0xC0 + x);
}
while(*Str != '\0')
{
Lcd_Write_State(Data, *Str++);
}
}
stm32f10x_it.c部分添加如下代码即可
void ADC_IRQHandler(void)
{
if (ADC_GetITStatus(ADCx,ADC_IT_EOC)==SET)
{
// 读取ADC的转换值
ADC_ConvertedValue = ADC_GetConversionValue(ADCx);
}
ADC_ClearITPendingBit(ADCx,ADC_IT_EOC);
}
延时部分的函数,可以采用软件延时,我这里采用的是系统的定时器,不再赘述。
总结:这个代码的编写没有多大难度,参考原有例程,将ADC和LCD部分代码整合,不要复用GPIO,在参考实际LCD1602A的数据手册,就能搞出个大概,再不断调试就能调出来。
PS:仅作为学习交流。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/190531.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...