首页 » 互联网 » 【根本】STM32F103C8T6制作舵机测试仪具体图文教程_初始化_时钟

【根本】STM32F103C8T6制作舵机测试仪具体图文教程_初始化_时钟

少女玫瑰心 2024-12-29 03:01:55 0

扫一扫用手机浏览

文章目录 [+]

这次紧张随着正点原子的开拓资料进行学习,没有利用战舰开拓板,而是利用STM32F103C8T6板子。
一是避免自己直接把例程的代码烧进开拓板,末了啥也没学到,在不同的板子间移植代码过程中,能够节制理解更多的根本知识和调试履历;二是这个小板子廉价易得,只要十块钱,和大几百的开拓板比较,它体积小、资源可不雅观,很适宜我的小项目,往后准备用来制作航模遥控器,敬请关注哈~

1.材料清单

1.STM32F103C8T6蓝色开拓板1(玄色板也可以)

【根本】STM32F103C8T6制作舵机测试仪具体图文教程_初始化_时钟 【根本】STM32F103C8T6制作舵机测试仪具体图文教程_初始化_时钟 互联网

2.USB转TTL模块1

【根本】STM32F103C8T6制作舵机测试仪具体图文教程_初始化_时钟 【根本】STM32F103C8T6制作舵机测试仪具体图文教程_初始化_时钟 互联网
(图片来自网络侵删)

3. ST-LINK V2仿真器下载器1(调试STM32性价比极高)

4. OLED屏幕(4管脚)1

5.10k电位器1(10k以上都可)

6. 杜邦线、面包板、导线、插针多少

2.电路连接

电位器:GND - PA0 - 3.3VOLED显示屏:GND 电源地VCC 接3.3v电源SCL 接PB8(SCL)SDA 接PB9(SDA)

ST-LINK V2接法:GND 电源地3V3 接3.3vSWCLK 接DCLKSWDIO 接DIO串口USB-TTL接法:GND 电源地3V3 接3.3vTXD 接PB7RXD 接PB6PWM输出:PB5

实物连接图如下:

3.安装keil5

安装及破解MDK(Keil5)教程 https://blog.csdn.net/weixin_42911200/article/details/81590158

把稳要安装Keil.STM32F1xx_DFP.2.3.0.pack支持包,由于我们要用STM32F103C8T6芯片的库函数编写。

库下载地址:https://www.keil.com/dd2/Pack/

博主已上传天翼云盘:https://cloud.189.cn/t/vyUBFzyuMBZr(访问码:6sng)

等待网页加载完,在列表里找到Keil,再找STMicroelectronics STM32F1 Series Device Support, Drivers and

4.新建工程

新建keil库函数工程 https://www.cnblogs.com/zeng-1995/p/11308622.html

与链接里面不同的因此下几个设置:

点击图标按钮1,打开Manage Run-Time Environment窗口,Device如下勾选,其他栏与链接中相同;

点击图标按钮2,打开Manage Project Items窗口,Groups和 Files如下设置:

点击图标按钮3,打开Options for Target窗口,点击顶部菜单按钮切换子窗口,依次如下设置:

点击Setting,打开Cortex-M Target Driver Setup窗口,如果SWDIO里面未显示序列号,则电脑须要更新ST-LINK驱动。

办理方法见链接 https://blog.csdn.net/qq_42041980/article/details/92015997

5.程序实现

掌握舵机的PWM:周期20ms,高电平时间0.5ms~2.5ms变革,可掌握舵机0~180°的角度变革,即每个高电平时间都对应舵机的一个角度。
但航模舵面的实际掌握中,不可能有180°变革,以是通用的高电平宽度实在是1ms~2ms。

详细可参考https://www.moz8.com/forum.php?mod=viewthread&tid=82875&highlight=%E8%88%B5%E6%9C%BA%E6%B5%8B%E8%AF%95%E4%BB%AA

掌握无刷电调所用的PWM旗子暗记高电平时间也是1ms~2ms,以是我们要实现的PWM旗子暗记周期20ms,高电平时间1ms~2ms。

我们利用ADC1读取电位器的电压采样值,并从0~4095范围的采样值转换到1000~2000,赋值给PWM输出。
TIM2定时触发ADC采样,通过DMA传输给变量所在的寄存器,取10次进行均值滤波,肃清抖动。

定时器触发ADC,DMA传输 http://www.openedv.com/forum.php?mod=viewthread&tid=277863&extra=&page=1

定时器TIM触发ADC采样,DMA搬运到内存 https://blog.csdn.net/qq_38410730/article/details/89921413

TIM3定时触发产生PWM旗子暗记,预分频72,频率1MHz,周期1us;自动装载值20 000,故PWM周期1us20 000=20ms。

紧张代码如下:

main.c文件-包含程序解释、主函数

/=============舵机测试仪==============芯片STM32F103C8T6,利用ADC读取电位器的电压采样值,0~4095转换到1000~2000,赋值给PWM输出。
TIM2定时触发ADC采样,通过DMA传输给变量ch1Value,取10次进行均值滤波。
掌握舵机的PWM:周期20ms,高电平时间0.5ms~2.5ms变革,可掌握舵机0~180°的角度变革, 但航模舵面的实际掌握中,不可能有180°变革,以是通用的高电平宽度实在是1ms~2ms电位器:GND - PA0 - 3.3VOLED显示屏:GND 电源地VCC 接3.3v电源SCL 接PB8(SCL)SDA 接PB9(SDA)串口USB-TTL接法:GND 电源地3V3 接3.3vTXD 接PB7RXD 接PB6ST-LINK V2接法:GND 电源地3V3 接3.3vSWCLK 接DCLKSWDIO 接DIOPWM输出:PB5by Bilibili 蔡子CaiZi/#include "config.h"#include "delay.h"#include "usart.h"#include "stm32f10x.h"#include "oled.h"#include "rtc.h" #include "stdio.h"#include "string.h" int main(){u8 txt[16]={0};delay_init();//初始化延时函数NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2,2位抢占优先级和2位子优先级usart_init(115200);//初始化串口1,波特率为115200TIM3_PWM_Init(19999,71);//预分频72,频率1MHz,周期1us;自动装载值20 000,故PWM周期1us20 000TIM2_Init(499,71);//1MHz,每500us采集一次;可设置9us以上,但过小影响OLED显示DMA1_Init();//DMA初始化GPIOA_Init();//PA初始化Adc_Init();//ADC初始化RTC_Init(); //RTC初始化OLED_Init();//初始化OLED OLED_Clear(); while (1){itoa(PWM1value,txt,10);//将int类型转换成10进制字符串//printf("采样值:%d\t舵量:%s\t",ch1Value,txt);//printf("当前韶光:%d:%d:%d\n",calendar.hour,calendar.min,calendar.sec);//OLED_Clear();//一贯清屏会造成闪烁strcat(txt," us");//合并字符串OLED_ShowString(6,3,txt,24); //位置6,3;字符大小2424点阵OLED_Refresh_Gram();delay_ms(1);}}

config.c文件-包含TIM/ GPIO/ ADC等初始化函数

#include "config.h"#include "delay.h"#include "usart.h"#include "sys.h"#include "rtc.h" volatile u16 ch1Value[10];//ADC采样值volatile u16 PWM1value;//掌握PWM占空比#define ADC1_DR_Address ((u32)0x4001244C)//ADC1的地址//通用定时器2中断初始化//这里时钟选择为APB1的2倍,而APB1为36M//arr:自动重装值。
//psc:时钟预分频数//这里利用的是定时器2掌握ADC定时采样void TIM2_Init(u16 arr,u16 psc){TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_OCInitTypeDef TIM_OCInitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能 //定时器TIM2初始化TIM_TimeBaseStructure.TIM_Period = arr; //设置不才一个更新事宜装入活动的自动重装载寄存器周期的值TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);//根据指定的参数初始化TIMx的韶光基数单位TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//选择定时器模式:TIM脉冲宽度调制模式1TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能TIM_OCInitStructure.TIM_Pulse = 9;//计数达到9产生中断TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;//输出极性:TIM输出比较极性低TIM_OC2Init(TIM2, & TIM_OCInitStructure);//初始化外设TIM2_CH2TIM_Cmd(TIM2, ENABLE); //使能TIMxTIM_CtrlPWMOutputs(TIM2, ENABLE); } //DMA1配置void DMA1_Init(void){DMA_InitTypeDef DMA_InitStructure;NVIC_InitTypeDef NVIC_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); //使能ADC1通道时钟//DMA1初始化DMA_DeInit(DMA1_Channel1);DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;//ADC1地址DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ch1Value; //ch1Value的内存地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //方向(从外设到内存)DMA_InitStructure.DMA_BufferSize = 10; //DMA缓存大小,存放10次采样值DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址固定,吸收一次数据后,设备地址禁止后移DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址不固定,吸收多次数据后,目标内存地址后移DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord ; //外设数据单位,定义外设数据宽度为16位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord ; //内存数据单位,HalfWord便是为16位DMA_InitStructure.DMA_Mode = DMA_Mode_Circular ; //DMA模式:循环传输DMA_InitStructure.DMA_Priority = DMA_Priority_High ; //DMA优先级:高DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //禁止内存到内存的传输DMA_Init(DMA1_Channel1, &DMA_InitStructure); //配置DMA1DMA_ITConfig(DMA1_Channel1,DMA_IT_TC, ENABLE);//使能传输完成中断 NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);DMA_Cmd(DMA1_Channel1,ENABLE);} //中断处理函数void DMA1_Channel1_IRQHandler(void){int sum=0;if(DMA_GetITStatus(DMA1_IT_TC1)!=RESET){//中断处理代码for(int i=0;i<10;i++){sum += ch1Value[i];}//均值滤波PWM1value = (int)map(sum/10,0,4092,1000,2000);sum=0;printf("%d\t",PWM1value);printf("当前韶光:%d:%d:%d\r\n",calendar.hour,calendar.min,calendar.sec);TIM_SetCompare2(TIM3,PWM1value);//输出给PWMDMA_ClearITPendingBit(DMA1_IT_TC1);//打消标志}}//GPIO配置,PA0void GPIOA_Init(void){GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟 //PA6 作为仿照通道输入引脚 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOA, &GPIO_InitStructure); } //初始化ADC//这里我们仅以规则通道为例//我们默认将开启通道0~3 void Adc_Init(void){ ADC_InitTypeDef ADC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能ADC1通道时钟 //ADC1初始化ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立ADC模式ADC_InitStructure.ADC_ScanConvMode = DISABLE; //关闭扫描办法ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//关闭连续转换模式ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2; //利用外部触发模式ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //采集数据右对齐ADC_InitStructure.ADC_NbrOfChannel = 1; //要转换的通道数目ADC_Init(ADC1, &ADC_InitStructure);RCC_ADCCLKConfig(RCC_PCLK2_Div6);//配置ADC时钟,为PCLK2的6分频,即12MHzADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);//配置ADC1通道0为239.5个采样周期 //使能ADC、DMAADC_DMACmd(ADC1,ENABLE);ADC_Cmd(ADC1,ENABLE); ADC_ResetCalibration(ADC1);//复位校准寄存器while(ADC_GetResetCalibrationStatus(ADC1));//等待校准寄存器复位完成 ADC_StartCalibration(ADC1);//ADC校准while(ADC_GetCalibrationStatus(ADC1));//等待校准完成ADC_ExternalTrigConvCmd(ADC1, ENABLE);//设置外部触发模式使能} //得到ADC值//ch:通道值 0~9u16 Get_Adc(u8 ch) { //设置指定ADC的规则组通道,一个序列,采样韶光ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );//ADC1,ADC通道,采样韶光为239.5个周期ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能指定的ADC1的软件转换启动功能while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束return ADC_GetConversionValue(ADC1);//返回最近一次ADC1规则组的转换结果} //ch:通道值 0~9,采样times次后作均值滤波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);}return temp_val/times;}//TIM3 PWM部分初始化 //PWM输出初始化//arr:自动重装值//psc:时钟预分频数void TIM3_PWM_Init(u16 arr,u16 psc){ GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//使能定时器3时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //使能GPIO外设和AFIO复用功能模块时钟GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射 TIM3_CH2->PB5 //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形GPIOB.5GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB //初始化TIM3TIM_TimeBaseStructure.TIM_Period = arr; //设置不才一个更新事宜装入活动的自动重装载寄存器周期的值TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的韶光基数单位//初始化TIM3 Channel2 PWM模式 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1,计数值<自动重装载值时,输出高电平 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC2 TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR2上的预装载寄存器 TIM_Cmd(TIM3, ENABLE); //使能TIM3} /函数解释:仿Arduino,将一个数字从一个范围重新映射到另一个范围也便是说,fromLow的值将映射到toLow,fromlhigh到toHigh的值等等。
/float map(float value,float fromLow,float fromHigh,float toLow,float toHigh){return ((value-fromLow)(toHigh-toLow)/(fromHigh-fromLow)+toLow);}

config.h-包含函数预定义和全局变量预定义

#ifndef __CONFIG_H#define __CONFIG_H#include "stm32f10x.h" //记得添加此头文件,由于config.c用到GPIO干系函数等#include "sys.h"extern volatile u16 ch1Value[10];//ADC采样值extern volatile u16 PWM1value;//掌握PWM占空比void TIM2_Init(u16 arr,u16 psc);//TIM2定时器初始化void TIM3_PWM_Init(u16 arr,u16 psc);//PB5定时器初始化void DMA1_Init(void);void GPIOA_Init(void);void Adc_Init(void);//ADC1初始化u16 Get_Adc(u8 ch); //获取一次ADC的值u16 Get_Adc_Average(u8 ch,u8 times);//ADC采样值进行均值滤波float map(float value,float fromLow,float fromHigh,float toLow,float toHigh);//映射函数#endif

oled.c-包含各种显示函数和IIC初始化

// // 功能描述 : 0.69寸OLED 接口演示例程(STM32F103C8T6 IIC)// 解释: // ----------------------------------------------------------------// GND 电源地// VCC 接3.3v电源// SCL 接PB8(SCL)// SDA 接PB9(SDA) //? #include "oled.h"#include "stdlib.h"#include "oledfont.h" #include "delay.h"//OLED的显存//存放格式如下.//[0]0 1 2 3 ... 127//[1]0 1 2 3 ... 127//[2]0 1 2 3 ... 127//[3]0 1 2 3 ... 127//[4]0 1 2 3 ... 127//[5]0 1 2 3 ... 127//[6]0 1 2 3 ... 127//[7]0 1 2 3 ... 127 ///IIC Start/void IIC_Start(void){ OLED_SCLK_Set() ;OLED_SDIN_Set();OLED_SDIN_Clr();OLED_SCLK_Clr();} ///IIC Stop/void IIC_Stop(void){OLED_SCLK_Set() ;//OLED_SCLK_Clr();OLED_SDIN_Clr();OLED_SDIN_Set();} void IIC_Wait_Ack(void){OLED_SCLK_Set() ;OLED_SCLK_Clr();}/// IIC Write byte/ void Write_IIC_Byte(unsigned char IIC_Byte){unsigned char i;unsigned char m,da;da=IIC_Byte;OLED_SCLK_Clr();for(i=0;i<8;i++){m=da;//OLED_SCLK_Clr();m=m&0x80;if(m==0x80){OLED_SDIN_Set();}else OLED_SDIN_Clr();da=da<<1;OLED_SCLK_Set();OLED_SCLK_Clr();} }/// IIC Write Command/void Write_IIC_Command(unsigned char IIC_Command){IIC_Start();Write_IIC_Byte(0x78); //Slave address,SA0=0IIC_Wait_Ack();Write_IIC_Byte(0x00);//write commandIIC_Wait_Ack();Write_IIC_Byte(IIC_Command); IIC_Wait_Ack();IIC_Stop();}/// IIC Write Data/void Write_IIC_Data(unsigned char IIC_Data){ IIC_Start(); Write_IIC_Byte(0x78);//D/C#=0; R/W#=0IIC_Wait_Ack(); Write_IIC_Byte(0x40);//write dataIIC_Wait_Ack(); Write_IIC_Byte(IIC_Data);IIC_Wait_Ack(); IIC_Stop();}void OLED_WR_Byte(unsigned dat,unsigned cmd){if(cmd){Write_IIC_Data(dat);}else {Write_IIC_Command(dat);} } /// fill_Picture/void fill_picture(unsigned char fill_Data){unsigned char m,n;for(m=0;m<8;m++){OLED_WR_Byte(0xb0+m,0);//page0-page1OLED_WR_Byte(0x00,0);//low column start addressOLED_WR_Byte(0x10,0);//high column start addressfor(n=0;n<128;n++){OLED_WR_Byte(fill_Data,1);}}} //坐标设置void OLED_Set_Pos(unsigned char x, unsigned char 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 ONOLED_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 OFFOLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF} //清屏函数,清完屏,全体屏幕是玄色的!和没点亮一样!!! void OLED_Clear(void) { u8 i,n; for(i=0;i<8;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); } //更新显示}//更新显存到OLEDu8 OLED_GRAM[128][8];void OLED_Refresh_Gram(void){u8 i,n; for(i=0;i<8;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(OLED_GRAM[n][i],OLED_DATA); } } //画点 //x:0~127//y:0~63//t:1 添补 0,清空 void OLED_DrawPoint(u8 x,u8 y,u8 t){u8 pos,bx,temp=0;if(x>127||y>63)return;//超出范围了.pos=7-y/8;bx=y%8;temp=1<<(7-bx);if(t)OLED_GRAM[x][pos]|=temp;else OLED_GRAM[x][pos]&=~temp; }//x1,y1,x2,y2 添补区域的对角坐标//确保x1<=x2;y1<=y2 0<=x1<=127 0<=y1<=63 //dot:0,清空;1,添补 void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot) { u8 x,y; for(x=x1;x<=x2;x++){for(y=y1;y<=y2;y++)OLED_DrawPoint(x,y,dot);} OLED_Refresh_Gram();//更新显示} //在指定位置显示一个字符,包括部分字符//x:0~127//y:0~63//mode:0,反白显示;1,正常显示 //size:选择字体 12/16/24void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode){ u8 temp,t,t1;u8 y0=y;u8 csize=(size/8+((size%8)?1:0))(size/2);//得到字体一个字符对应点阵集所占的字节数chr=chr-' ';//得到偏移后的值 for(t=0;t<csize;t++) { if(size==12)temp=asc2_1206[chr][t]; //调用1206字体else if(size==16)temp=asc2_1608[chr][t];//调用1608字体else if(size==24)temp=asc2_2412[chr][t];//调用2412字体else return;//没有的字库 for(t1=0;t1<8;t1++){if(temp&0x80)OLED_DrawPoint(x,y,mode);else OLED_DrawPoint(x,y,!mode);temp<<=1;y++;if((y-y0)==size){y=y0;x++;break;}} } }//m^n函数u32 mypow(u8 m,u8 n){u32 result=1; while(n--)result=m; return result;} //显示2个数字//x,y :出发点坐标 //len :数字的位数//size:字体大小12/16/24//mode:模式0,添补模式;1,叠加模式//num:数值(0~4294967295); void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size){ u8 t,temp;u8 enshow=0; for(t=0;t<len;t++){temp=(num/mypow(10,len-t-1))%10;if(enshow==0&&t<(len-1)){if(temp==0){OLED_ShowChar(x+(size/2)t,y,' ',size,1);continue;}else enshow=1; } OLED_ShowChar(x+(size/2)t,y,temp+'0',size,1); }} //显示字符串//x,y:出发点坐标 //size:字体大小12/16/24//p:字符串起始地址 void OLED_ShowString(u8 x,u8 y, u8 p,u8 size){ while((p<='~')&&(p>=' '))//判断是不是非法字符! { if(x>(128-(size/2))){x=0;y+=size;} if(y>(64-size)){y=x=0;OLED_Clear();} OLED_ShowChar(x,y,p,size,1); x+=size/2; p++; } } //显示汉字void OLED_ShowCHinese(u8 x,u8 y,u8 no){ u8 t,adder=0;OLED_Set_Pos(x,y); for(t=0;t<16;t++){OLED_WR_Byte(Hzk[2no][t],OLED_DATA);adder+=1; }OLED_Set_Pos(x,y+1); for(t=0;t<16;t++){OLED_WR_Byte(Hzk[2no+1][t],OLED_DATA);adder+=1; }}/功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7/void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[]){ unsigned int j=0; unsigned char 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++) { OLED_WR_Byte(BMP[j++],OLED_DATA); }}} //初始化SSD1306 void OLED_Init(void){ GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE); //使能B端口和AFIO复用功能模块时钟GPIO_PinRemapConfig(GPIO_Remap_I2C1, ENABLE);//IIC1重映射 -> PB8,9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速率50MHz GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOB8,9 GPIO_SetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_9); delay_ms(800);OLED_WR_Byte(0xAE,OLED_CMD);//--显示关闭OLED_WR_Byte(0x00,OLED_CMD);//---设置最小列地址OLED_WR_Byte(0x10,OLED_CMD);//---设置最大列地址OLED_WR_Byte(0x40,OLED_CMD);//--set start line address OLED_WR_Byte(0xB0,OLED_CMD);//--set page addressOLED_WR_Byte(0x81,OLED_CMD); // contract controlOLED_WR_Byte(0xFF,OLED_CMD);//--128 OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverseOLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 dutyOLED_WR_Byte(0xC0,OLED_CMD);//Com扫描方向,若显示的是镜对称,改为C8OLED_WR_Byte(0xD3,OLED_CMD);//-set display offsetOLED_WR_Byte(0x00,OLED_CMD);//OLED_WR_Byte(0xD5,OLED_CMD);//set osc divisionOLED_WR_Byte(0x80,OLED_CMD);//OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode offOLED_WR_Byte(0x05,OLED_CMD);//OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge PeriodOLED_WR_Byte(0xF1,OLED_CMD);//OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartionOLED_WR_Byte(0x12,OLED_CMD);//OLED_WR_Byte(0xDB,OLED_CMD);//set VcomhOLED_WR_Byte(0x30,OLED_CMD);//OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enableOLED_WR_Byte(0x14,OLED_CMD);//OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel} u8 itoa(int num,u8 str,int radix){char index[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//索引表unsigned unum;//存放要转换的整数的绝对值,转换的整数可能是负数int i=0,j,k;//i用来指示设置字符串相应位,转换之后i实在便是字符串的长度;转换后顺序是逆序的,有正负的情形,k用来指示调度顺序的开始位置;j用来指示调度顺序时的交流。
//获取要转换的整数的绝对值if(radix==10&&num<0)//要转换成十进制数并且是负数{unum=(unsigned)-num;//将num的绝对值赋给unumstr[i++]='-';//在字符串最前面设置为'-'号,并且索引加1}else unum=(unsigned)num;//若是num为正,直接赋值给unum //转换部分,把稳转换后是逆序的do{str[i++]=index[unum%(unsigned)radix];//取unum的末了一位,并设置为str对应位,指示索引加1unum/=radix;//unum去掉末了一位 }while(unum);//直至unum为0退出循环 str[i]='\0';//在字符串末了添加'\0'字符,c措辞字符串以'\0'结束。
//将顺序调度过来if(str[0]=='-') k=1;//如果是负数,符号不用调度,从符号后面开始调度else k=0;//不是负数,全部都要调度 u8 temp;//临时变量,交流两个值时用到for(j=k;j<=(i-1)/2;j++)//头尾逐一对称交流,i实在便是字符串的长度,索引最大值比长度少1{temp=str[j];//头部赋值给临时变量str[j]=str[i-1+k-j];//尾部赋值给头部str[i-1+k-j]=temp;//将临时变量的值(实在便是之前的头部值)赋给尾部} return str;//返回转换后的字符串}

oled.h-包含函数预定义和OLED显示所需的宏定义

/// 功能描述 : 0.69寸OLED 接口演示例程(STM32F103C8T6 IIC)// 解释: // ----------------------------------------------------------------// GND 电源地// VCC 接3.3v电源// SCL 接PB8(SCL)// SDA 接PB9(SDA) // ----------------------------------------------------------------//#ifndef __OLED_H#define __OLED_H #include "sys.h"#include "stdlib.h" #define OLED_MODE 0#define SIZE 8#define XLevelL0x00#define XLevelH0x10#define Max_Column128#define Max_Row64#defineBrightness0xFF #define X_WIDTH 128#define Y_WIDTH 64 //-----------------OLED IIC端口定义---------------- #define OLED_SCLK_Clr() GPIO_ResetBits(GPIOB,GPIO_Pin_8)//SCL#define OLED_SCLK_Set() GPIO_SetBits(GPIOB,GPIO_Pin_8) #define OLED_SDIN_Clr() GPIO_ResetBits(GPIOB,GPIO_Pin_9)//SDA#define OLED_SDIN_Set() GPIO_SetBits(GPIOB,GPIO_Pin_9) #define OLED_CMD 0//写命令#define OLED_DATA 1//写数据 //OLED掌握用函数void OLED_WR_Byte(unsigned dat,unsigned cmd); void OLED_Display_On(void);void OLED_Display_Off(void); void OLED_Init(void);void OLED_Clear(void);void OLED_Refresh_Gram(void);void OLED_DrawPoint(u8 x,u8 y,u8 t);void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot);void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode);void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size);void OLED_ShowString(u8 x,u8 y, u8 p,u8 size); void OLED_Set_Pos(unsigned char x, unsigned char y);void OLED_ShowCHinese(u8 x,u8 y,u8 no);void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[]);void fill_picture(unsigned char fill_Data);void IIC_Start(void);void IIC_Stop(void);void Write_IIC_Command(unsigned char IIC_Command);void Write_IIC_Data(unsigned char IIC_Data);void Write_IIC_Byte(unsigned char IIC_Byte);void IIC_Wait_Ack(void);u8 itoa(int num,u8 str,int radix);#endif

其他代码基本便是正点原子官方的文件了,全体工程文件已上传天翼云盘:

https://cloud.189.cn/t/uYniA3iM3iei(访问码:g914)

6.实现效果

串口调试助手查看串口输出

OLED显示

相关文章

IT高校论坛,探索未来科技教育的风向标

随着科技的飞速发展,我国IT行业呈现出蓬勃发展的态势。在此背景下,IT高校论坛应运而生,成为连接行业、学校、学生的重要桥梁。本文将...

互联网 2024-12-30 阅读0 评论0

IT黑管16,介绍新一代智能科技的未来

随着科技的飞速发展,我国在智能科技领域取得了举世瞩目的成就。近年来,IT黑管16作为一种新兴技术,逐渐引起了业界的关注。本文将围绕...

互联网 2024-12-30 阅读0 评论0