活动介绍

div转为图片base64无卡顿

时间: 2025-01-21 17:15:34 浏览: 37
### 将Div元素转换为Base64编码的图片 为了实现高效的转换并保持用户体验流畅,建议采用异步处理的方式。通过JavaScript库html2canvas可以捕获DOM节点作为图像,并将其转换成Base64字符串表示形式。 #### 使用html2canvas库的方法如下: 首先引入所需的外部资源文件: ```html <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script> ``` 定义用于触发截图操作的功能函数: ```javascript async function convertDivToImage(divId) { const element = document.getElementById(divId); try { // 开始绘制前显示加载指示器 showLoadingIndicator(); let canvas = await html2canvas(element, { scale: 2 }); // 获取base64格式的数据URL var base64image = canvas.toDataURL("image/png"); handleConvertedImage(base64image); } catch (error) { console.error('Error during conversion:', error); } finally { hideLoadingIndicator(); } } ``` 此方法利用`await`关键字等待Promise完成,从而确保不会阻塞主线程执行其他任务,有助于维持界面响应速度[^1]。 对于可能引起性能瓶颈的大尺寸或复杂结构的div内容,在调用上述功能之前应当考虑优化其样式和布局简化程度;另外还可以设置合适的缩放比例参数来平衡清晰度与渲染效率之间的关系。
阅读全文

相关推荐

为什么这一个buck文件加上adc或者是tim初始化就会使ole屏不亮,把这两个初始化去掉,oled屏又亮了,怎么解决(我用的使F4的板子和芯片)#include "stm32f4xx.h" #include "delay.h" #include "oled.h" #include "stdio.h" #include "stdlib.h" #include "arm_math.h" #include "pid.h" #include "./adc/bsp_adc.h" #include "tim.h" extern float voltage1, voltage2, voltage3; extern float Vout_actual; float Target= 12; // 目标输出电压12 float a; //extern __IO uint16_t ADC_ConvertedValue; extern uint16_t TIM_Advance_Impulse; int main(void) { OLED_Init(); arm_sin_f32(23); // Adc_Init(); TIM_Init(); while(1) { // a=pid_control (5 , 0.25, 0 ,Target ,Vout_actual); ADC_Read(); // float six = 6; char str[40]; sprintf(str,"Vout_actual = %.3f",Vout_actual); OLED_ShowString(WORD_WIDTH*0,WORD_HIGH*1,(u8 *)str,WORD_SIZE); OLED_Refresh_Gram(); delay_us(100); } } #include "./adc/bsp_adc.h" __IO uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL]={0}; float voltage1=0, voltage2=0, voltage3=0; float Vout_actual; static void ADC_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; /*=====================通道1======================*/ // 使能 GPIO 时钟 RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK1,ENABLE); // 配置 IO GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //不上拉不下拉 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(ADC_GPIO_PORT1, &GPIO_InitStructure); /*=====================通道2======================*/ // 使能 GPIO 时钟 RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK2,ENABLE); // 配置 IO GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //不上拉不下拉 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(ADC_GPIO_PORT2, &GPIO_InitStructure); /*=====================通道3=======================*/ // 使能 GPIO 时钟 RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK3,ENABLE); // 配置 IO GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //不上拉不下拉 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(ADC_GPIO_PORT3, &GPIO_InitStructure); } static void ADC_Mode_Config(void) { DMA_InitTypeDef DMA_InitStructure; ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; // ------------------DMA Init 结构体参数 初始化-------------------------- // ADC1使用DMA2,数据流0,通道0,这个是手册固定死的 // 开启DMA时钟 RCC_AHB1PeriphClockCmd(ADC_DMA_CLK, ENABLE); // 外设基址为:ADC 数据寄存器地址 DMA_InitStructure.DMA_PeripheralBaseAddr = RHEOSTAT_ADC_DR_ADDR; // 存储器地址,实际上就是一个内部SRAM的变量 DMA_InitStructure.DMA_Memory0BaseAddr = (u32)ADC_ConvertedValue; // 数据传输方向为外设到存储器 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // 缓冲区大小为,指一次传输的数据量 DMA_InitStructure.DMA_BufferSize = RHEOSTAT_NOFCHANEL; // 外设寄存器只有一个,地址不用递增 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 存储器地址固定 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // // 外设数据大小为半字,即两个字节 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 存储器数据大小也为半字,跟外设数据大小相同 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 循环传输模式 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响 DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 禁止DMA FIFO ,使用直连模式 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; // FIFO 大小,FIFO模式禁止时,这个不用配置 DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; // 选择 DMA 通道,通道存在于流中 DMA_InitStructure.DMA_Channel = ADC_DMA_CHANNEL; //初始化DMA流,流相当于一个大的管道,管道里面有很多通道 DMA_Init(ADC_DMA_STREAM, &DMA_InitStructure); // 使能DMA传输完成中断 DMA_ITConfig(ADC_DMA_STREAM, DMA_IT_TC, ENABLE); // 使能DMA流 DMA_Cmd(ADC_DMA_STREAM, ENABLE); // 开启ADC时钟 RCC_APB2PeriphClockCmd(ADC_CLK , ENABLE); // -------------------ADC Common 结构体 参数 初始化------------------------ // 独立ADC模式 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; // 时钟为fpclk x分频 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; // 禁止DMA直接访问模式 ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; // 采样时间间隔 ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; ADC_CommonInit(&ADC_CommonInitStructure); // -------------------ADC Init 结构体 参数 初始化-------------------------- ADC_StructInit(&ADC_InitStructure); // ADC 分辨率 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; // 扫描模式,多通道采集需要 ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 连续转换 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //禁止外部边沿触发 ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //外部触发通道,本例子使用软件触发,此值随便赋值即可 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; //数据右对齐 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //转换通道 1个 ADC_InitStructure.ADC_NbrOfConversion = RHEOSTAT_NOFCHANEL; ADC_Init(ADC_, &ADC_InitStructure); //--------------------------------------------------------------------------- // 配置 ADC 通道转换顺序和采样时间周期 ADC_RegularChannelConfig(ADC_, ADC_CHANNEL1, 1, ADC_SampleTime_15Cycles); ADC_RegularChannelConfig(ADC_, ADC_CHANNEL2, 2, ADC_SampleTime_15Cycles); ADC_RegularChannelConfig(ADC_, ADC_CHANNEL3, 3, ADC_SampleTime_15Cycles); // 使能DMA请求 after last transfer (Single-ADC mode) ADC_DMARequestAfterLastTransferCmd(ADC_, ENABLE); // 使能ADC DMA ADC_DMACmd(ADC_, ENABLE); // 使能ADC ADC_Cmd(ADC_, ENABLE); //开始adc转换,软件触发 ADC_SoftwareStartConv(ADC_); } static void ADC_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置DMA NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } void ADC_Read(void) { voltage1=(float)ADC_ConvertedValue[0]*0.000244140625*3.3; voltage2=(float)ADC_ConvertedValue[1]*0.000244140625*3.3; voltage3=(float)ADC_ConvertedValue[2]*0.000244140625*3.3; Vout_actual = voltage1; } void Adc_Init(void) { ADC_GPIO_Config(); ADC_Mode_Config(); ADC_NVIC_Config(); } #ifndef __BSP_ADC_H #define __BSP_ADC_H #include "stm32f4xx.h" #define RHEOSTAT_NOFCHANEL 3 /*=====================通道1 IO======================*/ // ADC IO宏定义 #define ADC_GPIO_PORT1 GPIOE #define ADC_GPIO_PIN1 GPIO_Pin_5 #define ADC_GPIO_CLK1 RCC_AHB1Periph_GPIOE #define ADC_CHANNEL1 ADC_Channel_15 /*=====================通道2 IO ======================*/ // ADC IO宏定义 #define ADC_GPIO_PORT2 GPIOA #define ADC_GPIO_PIN2 GPIO_Pin_2 #define ADC_GPIO_CLK2 RCC_AHB1Periph_GPIOA #define ADC_CHANNEL2 ADC_Channel_2 /*=====================通道3 IO ======================*/ // ADC IO宏定义 #define ADC_GPIO_PORT3 GPIOA #define ADC_GPIO_PIN3 GPIO_Pin_3 #define ADC_GPIO_CLK3 RCC_AHB1Periph_GPIOA #define ADC_CHANNEL3 ADC_Channel_3 // ADC 序号宏定义 #define ADC_ ADC1 #define ADC_CLK RCC_APB2Periph_ADC1 // ADC DR寄存器宏定义,ADC转换后的数字值则存放在这里 #define RHEOSTAT_ADC_DR_ADDR ((u32)ADC1+0x4c) // ADC DMA 通道宏定义,这里我们使用DMA传输 #define ADC_DMA_CLK RCC_AHB1Periph_DMA2 #define ADC_DMA_CHANNEL DMA_Channel_0 #define ADC_DMA_STREAM DMA2_Stream0 void Adc_Init(void); void ADC_Read(void); #endif /* __BSP_ADC_H */ #include "tim.h" uint16_t TIM1_Impluse = 4200;//预设占空比 float z = 0; const uint32_t spwm[400] = { 4200,4265,4331,4397,4463,4529,4595,4660,4726,4791,4857,4922,4987,5051,5116,5180, 5244,5308,5371,5434,5497,5560,5622,5684,5746,5807,5868,5928,5988,6047,6106,6165, 6223,6280,6337,6394,6450,6505,6560,6615,6668,6721,6774,6826,6877,6927,6977,7026, 7075,7122,7169,7216,7261,7306,7350,7393,7436,7477,7518,7558,7597,7636,7673,7710, 7746,7781,7815,7848,7880,7911,7942,7971,8000,8027,8054,8080,8105,8128,8151,8173, 8194,8214,8233,8251,8268,8283,8298,8312,8325,8337,8348,8358,8366,8374,8381,8387, 8391,8395,8397,8399,8400,8399,8397,8395,8391,8387,8381,8374,8366,8358,8348,8337, 8325,8312,8298,8283,8268,8251,8233,8214,8194,8173,8151,8128,8105,8080,8054,8027, 8000,7971,7942,7911,7880,7848,7815,7781,7746,7710,7673,7636,7597,7558,7518,7477, 7436,7393,7350,7306,7261,7216,7169,7122,7075,7026,6977,6927,6877,6826,6774,6721, 6668,6615,6560,6505,6450,6394,6337,6280,6223,6165,6106,6047,5988,5928,5868,5807, 5746,5684,5622,5560,5497,5434,5371,5308,5244,5180,5116,5051,4987,4922,4857,4791, 4726,4660,4595,4529,4463,4397,4331,4265,4200,4134,4068,4002,3936,3870,3804,3739, 3673,3608,3542,3477,3412,3348,3283,3219,3155,3091,3028,2965,2902,2839,2777,2715, 2653,2592,2531,2471,2411,2352,2293,2234,2176,2119,2062,2005,1949,1894,1839,1784, 1731,1678,1625,1573,1522,1472,1422,1373,1324,1277,1230,1183,1138,1093,1049,1006, 963,922,881,841,802,763,726,689,653,618,584,551,519,488,457,428, 399,372,345,319,294,271,248,226,205,185,166,148,131,116,101,87, 74,62,51,41,33,25,18,12,8,4,2,0,0,0,2,4, 8,12,18,25,33,41,51,62,74,87,101,116,131,148,166,185, 205,226,248,271,294,319,345,372,399,428,457,488,519,551,584,618, 653,689,726,763,802,841,881,922,963,1006,1049,1093,1138,1183,1230,1277, 1324,1373,1422,1472,1522,1573,1625,1678,1731,1784,1839,1894,1949,2005,2062,2119, 2176,2234,2293,2352,2411,2471,2531,2592,2653,2715,2777,2839,2902,2965,3028,3091, 3155,3219,3283,3348,3412,3477,3542,3608,3673,3739,3804,3870,3936,4002,4068,4134 }; //TIM1的GPIO static void TIM_GPIO_Config(void) { GPIO_InitTypeDef TIM_GPIO_InitStruct; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB, ENABLE);//开钟 /*-----------------------------PA8,PA7------------------------------------*/ GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_TIM1);//引脚复用 主 PA8,PA7 GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_TIM1);//引脚复用 补 TIM_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //模拟模式GPIO_Mode_AN/F TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8; //引脚 TIM_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //高速 TIM_GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽 TIM_GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); //写入 TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7; GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); /*-----------------------------------------------------------------------*/ /*-----------------------------PA9,PB14------------------------------------*/ GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_TIM1);//引脚复用 主 GPIO_PinAFConfig(GPIOB,GPIO_PinSource14,GPIO_AF_TIM1);//引脚复用 补 TIM_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //模拟模式GPIO_Mode_AN/F TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; //引脚 TIM_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //高速 TIM_GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽 TIM_GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); //写入 TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14; GPIO_Init(GPIOB, &TIM_GPIO_InitStruct); /*-----------------------------------------------------------------------*/ /*-----------------------------PA10,PB1------------------------------------*/ GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_TIM1);//引脚复用 主 GPIO_PinAFConfig(GPIOB,GPIO_PinSource1,GPIO_AF_TIM1);//引脚复用 补 TIM_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //模拟模式GPIO_Mode_AN/F TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; //引脚 TIM_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //高速 TIM_GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽 TIM_GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); //写入 TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1; GPIO_Init(GPIOB, &TIM_GPIO_InitStruct); /*-----------------------------------------------------------------------*/ // TIM_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN; //模拟模式 pa6死刹 // TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; //引脚 // TIM_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //高速 // TIM_GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽 // TIM_GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; //浮空 // GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); //写入 } //TIM1 static void TIM_A1_Mode_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_OCInitTypeDef TIM_OCInitStruct; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);///使能时钟 //168MHZ->20kHZ 主频/(计数+1)*(预分频系数+1) //168MHz/8 * 1050 = 20khz /*-----------------------------基本结构体------------------------------------*/ TIM_TimeBaseInitStructure.TIM_Period = (8400-1); //自动重装载值 TIM_TimeBaseInitStructure.TIM_Prescaler=(1-1); //定时器分频 TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //1分频 TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0; //不需要重复计数 TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStructure); //初始化TIM /*-----------------------------基本结构体------------------------------------*/ /*-----------------------------输出比较------------------------------------*/ TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; //pwm模式选择 TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; ///使能输出通道 TIM_OCInitStruct.TIM_OutputNState = TIM_OutputNState_Enable; //使能互补通道 TIM_OCInitStruct.TIM_Pulse = TIM1_Impluse; //预设占空比 TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; //PWM1和2中的CH和CCR之间值的大小(多用pwm1的模式1) TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High; //当使用了刹车功能时,两路PWM1和2都会被强制禁止,进而输出我们配置的的空闲先状态 TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set; //刹车时输出通道的状态 Set = high TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Reset; //刹车时互补通道的状态 Reset = low TIM_OC1Init(TIM1, &TIM_OCInitStruct); //使能通道1 TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); /* 使能通道1重载 */ TIM_OCInitStruct.TIM_Pulse = TIM1_Impluse; TIM_OC2Init(TIM1, &TIM_OCInitStruct); TIM_OC2PreloadConfig(TIM1,TIM_OCPreload_Enable); TIM_OCInitStruct.TIM_Pulse = TIM1_Impluse; TIM_OC3Init(TIM1, &TIM_OCInitStruct); TIM_OC3PreloadConfig(TIM1,TIM_OCPreload_Enable); /*-----------------------------输出比较------------------------------------*/ /*-----------------------------死区刹车------------------------------------*/ TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; //开启死区 TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; //开启1空闲状态 TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; //不同的锁定级别 (看BDTR寄存器) TIM_BDTRInitStructure.TIM_DeadTime = 20; //刹车时间,(看BDTR寄存器中的DTG[7:0]) //11转换成二进制为0000 1011 死区时间看[7;5]位,此处为000 TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable; //允许刹车 //BKIN 测到低电平 比较信号禁止 TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; //高极性 TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; //自动输出使能(刹车输入无效) TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure); //写入 /*-----------------------------死区刹车------------------------------------*/ TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); //允许定时器更新中断 | TIM_IT_Trigger TIM_Cmd(TIM1,ENABLE); //使能定时器 TIM_CtrlPWMOutputs(TIM1, ENABLE); //主动输出使能 } static void TIM_A1_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; /*-----------------------------中断------------------------------------*/ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //分组 NVIC_InitStructure.NVIC_IRQChannel=TIM1_UP_TIM10_IRQn; //定时器1中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能中断 NVIC_Init(&NVIC_InitStructure); //写入 /*-----------------------------中断------------------------------------*/ } void TIM_Init(void) { TIM_A1_NVIC_Config(); TIM_GPIO_Config(); TIM_A1_Mode_Config(); } #ifndef __TIM_H #define __TIM_H #include "sys.h" void TIM_Init(void); #endif #include "stm32f4xx_it.h" #include "oled.h" #include <math.h> #include "./adc/bsp_adc.h" #include "pid.h" extern uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL]; extern float voltage1; uint16_t TIM_Advance_Impulse ;//高级定时器占空比 extern float Vout_actual; float Vout_set; // 目标输出电压 float pid_out; extern float pid_out; void TIM1_UP_IRQHandler(void) { if(TIM_GetITStatus(TIM1,TIM_IT_Update) == SET) { Vout_actual = voltage1; pid_out = pid_control (5 , 0.25, 0 ,Vout_set ,Vout_actual); TIM1->CCR1 = pid_out; TIM_ClearITPendingBit(TIM1, TIM_IT_Update); } } void DMA2_Stream0_IRQHandler(void) { // 检查传输完成中断标志 if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0) != RESET) { // 清除中断标志 DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0); // 调用ADC_Read计算电压 ADC_Read(); } } void NMI_Handler(void) { } void HardFault_Handler(void) { /* Go to infinite loop when Hard Fault exception occurs */ while (1) {} } void MemManage_Handler(void) { /* Go to infinite loop when Memory Manage exception occurs */ while (1) {} } void BusFault_Handler(void) { /* Go to infinite loop when Bus Fault exception occurs */ while (1) {} } void UsageFault_Handler(void) { /* Go to infinite loop when Usage Fault exception occurs */ while (1) {} } void DebugMon_Handler(void) { } void SVC_Handler(void) { } void PendSV_Handler(void) { } void SysTick_Handler(void) { } #include "pid.h" float kp, ki, kd; // PID参数 float last_error = 0,last_error_2 = 0 , last_output, setpoint, input, output; float pid_control(float KP , float KI , float KD , float Set_Point , float Now_Point) { kp = KP; ki = KI; kd = KD; setpoint = Set_Point; input = Now_Point; float error = setpoint - input; float delta_error = error - last_error; output += kp*delta_error + ki*error + kd*(error-2*last_error+last_error_2); last_error_2 = last_error; last_error = error; last_output = output; //输出限幅 // if(output >= 100.0f ) output = 100.0f; return output; } #ifndef __PID_H_ #define __PID_H_ float pid_control(float KP , float KI , float KD , float Set_Point , float Now_Point); #endif #include "oled.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 u8 OLED_GRAM[128][8]; #if OLED_MODE==0 //向SSD1106写入一个字节。 //dat:要写入的数据/命令 //cmd:数据/命令标志 0,表示命令;1,表示数据; void OLED_WR_Byte(u8 dat,u8 cmd) { u8 i; OLED_DC=cmd; OLED_CS=0; for(i=0;i<8;i++) { OLED_SCL=0; if(dat&0x80) OLED_SDA=1; else OLED_SDA=0; OLED_SCL=1; dat<<=1; } OLED_CS=1; OLED_DC=1; } #endif #if OLED_MODE==1 //向SSD1106写入一个字节。 //dat:要写入的数据/命令 //cmd:数据/命令标志 0,表示命令;1,表示数据; void OLED_WR_Byte(u8 dat,u8 cmd) { OLED_DATA_OUT(dat); OLED_RST=cmd; OLED_CS=0; OLED_WR=0; OLED_WR=1; OLED_CS=1; OLED_DC=1; } #endif #if OLED_MODE==2 void OLED_WR_Byte(u8 dat,u8 cmd) { } #endif //更新显存到LCD 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); } } 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)|0x01,OLED_CMD); } //开启OLED显示 void OLED_Display_On(void) { OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令 OLED_WR_Byte(0X14,OLED_CMD); //DCDC ON OLED_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 OFF OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF } //清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!! void OLED_Clear(void) { u8 i,n; for(i=0;i<8;i++) { for(n=0;n<128;n++) { OLED_GRAM[n][i]=0; } } OLED_Refresh_Gram();//更新显示 } //画点 //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; } void OLED_DrawLine(u8 x1, u8 y1, u8 x2, u8 y2) { u16 t; int xerr=0,yerr=0,delta_x,delta_y,distance; int incx,incy,uRow,uCol; delta_x=x2-x1; //计算坐标增量 delta_y=y2-y1; uRow=x1; uCol=y1; if(delta_x>0)incx=1; //设置单步方向 else if(delta_x==0)incx=0;//垂直线 else {incx=-1;delta_x=-delta_x;} if(delta_y>0)incy=1; else if(delta_y==0)incy=0;//水平线 else{incy=-1;delta_y=-delta_y;} if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 else distance=delta_y; for(t=0;t<=distance+1;t++ )//画线输出 { OLED_DrawPoint(uRow,uCol,1);//画点 xerr+=delta_x ; yerr+=delta_y ; if(xerr>distance) { xerr-=distance; uRow+=incx; } if(yerr>distance) { yerr-=distance; uCol+=incy; } } } void OLED_DrawRectangle(u8 x1, u8 y1, u8 x2, u8 y2) { OLED_DrawLine(x1,y1,x2,y1); OLED_DrawLine(x1,y1,x1,y2); OLED_DrawLine(x1,y2,x2,y2); OLED_DrawLine(x2,y1,x2,y2); } //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/24 void 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=ascii_1206[chr][t]; //调用1206字体 else if(size==16)temp=ascii_1608[chr][t]; //调用1608字体 else if(size==24)temp=ascii_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 oled_pow(u8 m,u8 n) { u32 result=1; while(n--)result*=m; return result; } //显示2个数字 //x,y :起点坐标 //len :数字的位数 //size:字体大小 //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/oled_pow(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:字体大小 //*p:字符串起始地址 void OLED_ShowString(u8 x,u8 y,const 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++; } } //显示汉字 //x,y:起点坐标 //pos:数组位置汉字显示 //size:字体大小 //mode:0,反白显示;1,正常显示 void OLED_ShowFontHZ(u8 x,u8 y,u8 pos,u8 size,u8 mode) { u8 temp,t,t1; u8 y0=y; u8 csize=(size/8+((size%8)?1:0))*(size);//得到字体一个字符对应点阵集所占的字节数 if(size!=12&&size!=16&&size!=24&&size!=32)return; //不支持的size for(t=0;t<csize;t++) { if(size==12)temp=FontHzk_12[pos][t]; //调用1206字体 else if(size==16)temp=FontHzk_16[pos][t]; //调用1608字体 else if(size==24)temp=FontHzk_24[pos][t]; //调用2412字体 else if(size==32)temp=FontHzk_32[pos][t]; //调用3216字体 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; } } } } //显示BMP图片128×64 //起始点坐标(x,y),x的范围0~127,y为页的范围0~7 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++) { OLED_WR_Byte(BMP[j++],OLED_DATA); } } } //GND 接电源地 //VCC 接5V或3.3v电源 //D0 接PD6(SCL) //D1 接PD7(SDA) //RES 接PD4 //DC 接PD5 //CS 接PD3 void OLED_Init() { GPIO_InitTypeDef GPIO_InitStructure; #if OLED_MODE==0 //4线SPI模式 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE|RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_6;//管脚设置 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//不拉 GPIO_Init(GPIOE,&GPIO_InitStructure); //初始化结构体 GPIO_SetBits(GPIOE,GPIO_Pin_2|GPIO_Pin_6); //拉高电平 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_13;//管脚设置 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//不拉 GPIO_Init(GPIOC,&GPIO_InitStructure); //初始化结构体 GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_13); //拉高电平 OLED_Clear(); #endif #if OLED_MODE==1 //8080模式 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOC,ENABLE); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;//管脚设置 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉 GPIO_Init(GPIOD,&GPIO_InitStructure); //初始化结构体 GPIO_SetBits(GPIOD,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); GPIO_InitStructure.GPIO_Pin = 0XFF; //PC0-7 GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_SetBits(GPIOC,0xFF); //PC0-7输出高 #endif #if OLED_MODE==2 //IIC模式 #endif OLED_RST=1; delay_ms(100); OLED_RST=0; delay_ms(100); OLED_RST=1; OLED_WR_Byte(0xAE,OLED_CMD); //关闭显示 OLED_WR_Byte(0xD5,OLED_CMD); //设置时钟分频因子,震荡频率 OLED_WR_Byte(80,OLED_CMD); //[3:0],分频因子;[7:4],震荡频率 OLED_WR_Byte(0xA8,OLED_CMD); //设置驱动路数 OLED_WR_Byte(0X3F,OLED_CMD); //默认0X3F(1/64) OLED_WR_Byte(0xD3,OLED_CMD); //设置显示偏移 OLED_WR_Byte(0X00,OLED_CMD); //默认为0 OLED_WR_Byte(0x40,OLED_CMD); //设置显示开始行 [5:0],行数. OLED_WR_Byte(0x8D,OLED_CMD); //电荷泵设置 OLED_WR_Byte(0x14,OLED_CMD); //bit2,开启/关闭 OLED_WR_Byte(0x20,OLED_CMD); //设置内存地址模式 OLED_WR_Byte(0x02,OLED_CMD); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10; OLED_WR_Byte(0xA1,OLED_CMD); //段重定义设置,bit0:0,0->0;1,0->127; OLED_WR_Byte(0xC0,OLED_CMD); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数 OLED_WR_Byte(0xDA,OLED_CMD); //设置COM硬件引脚配置 OLED_WR_Byte(0x12,OLED_CMD); //[5:4]配置 OLED_WR_Byte(0x81,OLED_CMD); //对比度设置 OLED_WR_Byte(0xEF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮) OLED_WR_Byte(0xD9,OLED_CMD); //设置预充电周期 OLED_WR_Byte(0xf1,OLED_CMD); //[3:0],PHASE 1;[7:4],PHASE 2; OLED_WR_Byte(0xDB,OLED_CMD); //设置VCOMH 电压倍率 OLED_WR_Byte(0x30,OLED_CMD); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc; OLED_WR_Byte(0xA4,OLED_CMD); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏) OLED_WR_Byte(0xA6,OLED_CMD); //设置显示方式;bit0:1,反相显示;0,正常显示 OLED_WR_Byte(0xAF,OLED_CMD); //开启显示 OLED_Clear(); } #ifndef _oled_H #define _oled_H #include "sys/system.h" #include "stdlib.h" #define WORD_SIZE 12 #define X_OFFSET_WORD 0 #define Y_OFFSET_WORD 0 #define X_OFFSTE_PIXEL 0 #define Y_OFFSTE_PIXEL 0 #if WORD_SIZE != 12 && WORD_SIZE != 16 && WORD_SIZE != 24 #define WORD_SIZE 12 #endif #if WORD_SIZE == 24 #define WORD_WIDTH 12 #define WORD_HIGH 24 #endif #if WORD_SIZE == 16 #define WORD_WIDTH 8 #define WORD_HIGH 16 #endif #if WORD_SIZE == 12 #define WORD_WIDTH 6 #define WORD_HIGH 12 #endif //OLED模式设置 //0:4线串行SPI模式 //1:并行8080模式 //2:IIC模式 #define OLED_MODE 0 #define SIZE 16 #define XLevelL 0x00 #define XLevelH 0x10 #define Max_Column 128 #define Max_Row 64 #define Brightness 0xFF #define X_WIDTH 128 #define Y_WIDTH 64 #if OLED_MODE==0 //OLDE-SPI4线控制管脚定义 #define OLED_SCL PCout(1) #define OLED_SDA PCout(0) #define OLED_RST PCout(13) #define OLED_DC PEout(6) #define OLED_CS PEout(2) #endif #if OLED_MODE==1 //OLDE-8080总线控制管脚定义 #define OLED_CS PDout(3) #define OLED_RST PDout(4) #define OLED_DC PDout(5) #define OLED_WR PDout(6) #define OLED_RD PDout(7) #define OLED_DATA_OUT(x) GPIO_Write(GPIOC,x);//输出 #endif #if OLED_MODE==2 //OLDE-IIC总线控制管脚定义 #endif #define OLED_CMD 0 //写命令 #define OLED_DATA 1 //写数据 //OLED控制用函数 void OLED_WR_Byte(u8 dat,u8 cmd); void OLED_Display_On(void); void OLED_Display_Off(void); void OLED_Set_Pos(unsigned char x, unsigned char y); void OLED_Init(void); void OLED_Refresh_Gram(void); void OLED_Clear(void); void OLED_DrawPoint(u8 x,u8 y,u8 t); void OLED_DrawLine(u8 x1, u8 y1, u8 x2, u8 y2); void OLED_DrawRectangle(u8 x1, u8 y1, u8 x2, u8 y2); 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,const u8 *p,u8 size); void OLED_ShowFontHZ(u8 x,u8 y,u8 pos,u8 size,u8 mode); void OLED_DrawBMP(u8 x0, u8 y0,u8 x1, u8 y1,u8 BMP[]); #endif

<template> <view> <view class="map" id="mapDiv" style="width: 100%;height: 67vh;z-index: 0;position: relative;" :prop="dataOption" :change:prop="Trenderjs.initTMap" :change:renderTrigger="Trenderjs.handleMessage" :renderTrigger="triggerCounter"> </view> </view> </template> <script> export default { data() { return { triggerCounter: 0, isProcessing: false, message: null }; }, props: { dataOption: { type: String, default: '' }, }, methods: { renderjsData() { if (this.isProcessing) return; this.isProcessing = true; this.triggerCounter++; }, someMethodInVue(newVal) { this.$emit('childEvent', newVal); this.message = newVal; this.isProcessing = false; } } }; </script> <script module="Trenderjs" lang="renderjs"> var control; export default { data() { return { tk: '27657afc3318f8f2166fceba83427734', options: { lng: '104.397894', lat: '31.126855', }, Tmap: null, gisDataObj: {}, gisData: {}, geocode: null, gisPointLngLat: {}, // 定位优化相关变量 positionHistory: [], // 位置历史记录 maxHistorySize: 10, // 最大历史记录数 realTimeMarker: null, // 实时定位标记 realTimeLabel: null, // 实时定位标签 // 动画相关变量 animationTarget: null, // 动画目标位置 animationStep: 0, // 动画步数 animationTimer: null, // 动画计时器 animationDuration: 500, // 动画时长(ms) hasFitViewOnFirstLocation: false, // 方向相关变量 currentHeading: 0, // 当前设备方向(度数) compassWatchId: null, // 指南针监听ID isCompassAvailable: false, // 是否支持指南针 lastHeadingUpdate: 0, // 上次方向更新时间 headingFilterFactor: 0.1, // 方向滤波系数 // 新增:基础图标和缓存 baseIcon: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAzMCIgd2lkdGg9IjMwIiBoZWlnaHQ9IjMwIj48cGF0aCBkPSJNMTUgMkwyOCAyOC4ySDJ6IiBmaWxsPSIjM0Q4NUZGIi8+PC9zdmc+', iconCache: {}, // 缓存不同角度的图标 lastRenderedHeading: null // 上次渲染的角度 } }, mounted() { if (!window.T) { const script = document.createElement('script') script.src = 'http://api.tianditu.gov.cn/api?v=4.0&tk=' + this.tk document.head.appendChild(script) script.onload = this.initChartsRender.bind() } else { this.initMap(); } this.initCompass(); }, methods: { // 初始化地图 initMap() { const { lng, lat } = this.options; this.Tmap = new T.Map('mapDiv'); this.Tmap.centerAndZoom(new T.LngLat(lng, lat), 15); this.Tmap.setStyle("indigo"); // this.Tmap.disableDoubleClickZoom(); // this.Tmap.disableScrollWheelZoom(); // this.Tmap.disableInertia(); // this.Tmap.disableKeyboard(); this.geocode = new T.Geocoder(); // control = new T.Control.Zoom(); // this.Tmap.addControl(control); // control.setPosition(T_ANCHOR_BOTTOM_RIGHT); }, // 若没有加载地图方法 initChartsRender() { this.initMap(); }, // 初始化地图数据 initTMap(newValue, oldValue) { let that = this; // 清除旧的定位监听 that._watchId && plus.geolocation.clearWatch(that._watchId); // 启动新的定位监听 that._watchId = plus.geolocation.watchPosition( position => that._handlePosition(position), err => console.log('err', err), { provider: 'system', enableHighAccuracy: true, maximumAge: 0, timeout: 10000 } ); // 处理传入的地图数据 if (newValue) { setTimeout(function() { try { that.gisDataObj = JSON.parse(newValue); if (that.gisDataObj.hasOwnProperty('data') && that.gisDataObj.data) { that.gisData = JSON.parse(that.gisDataObj.data); if (that.gisData.hasOwnProperty('data') && that.gisData.data) { let gisPoint = JSON.parse(that.gisData.data); that.gisPointLngLat = gisPoint; // 设置中心点 let centerLng, centerLat; if (that.gisData.type == 'marker') { centerLng = gisPoint.lng; centerLat = gisPoint.lat; } else if (that.gisData.type == 'polyline' || that.gisData.type == 'polygon') { centerLng = gisPoint[0].lng; centerLat = gisPoint[0].lat; } else { centerLng = '104.397894'; centerLat = '31.126855'; } that.Tmap.centerAndZoom(new T.LngLat(centerLng, centerLat), 15); // 绘制地图元素 that._drawMapElements(); } } } catch (e) { console.error('数据解析错误:', e); } }, 1000); } }, // 处理定位点 - 核心优化 _handlePosition(position) { const coords = position.coords; // console.log("position: " + JSON.stringify(position)) const now = Date.now(); const newPoint = { lng: coords.longitude, lat: coords.latitude, accuracy: coords.accuracy, timestamp: now }; // 添加到历史记录 this.positionHistory.push(newPoint); if (this.positionHistory.length > this.maxHistorySize) { this.positionHistory.shift(); } // 使用卡尔曼滤波平滑位置 const smoothedPoint = this._kalmanFilter(newPoint); // 启动平滑动画 this._startAnimation(smoothedPoint); // 只在第一次定位时适配视野 if (!this.hasFitViewOnFirstLocation) { this._fitAllPoints(); this.hasFitViewOnFirstLocation = true; } }, // 卡尔曼滤波算法 _kalmanFilter(newPoint) { // 初始化状态 if (!this.kalmanState) { this.kalmanState = { x: newPoint.lng, y: newPoint.lat, vx: 0, // x方向速度 vy: 0, // y方向速度 P: [ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1] ], // 协方差矩阵 lastTime: newPoint.timestamp }; return newPoint; } // 时间差(秒) const dt = (newPoint.timestamp - this.kalmanState.lastTime) / 1000; this.kalmanState.lastTime = newPoint.timestamp; // 状态转移矩阵 const F = [ [1, 0, dt, 0], [0, 1, 0, dt], [0, 0, 1, 0], [0, 0, 0, 1] ]; // 过程噪声协方差矩阵 const Q = [ [Math.pow(dt, 4) / 4, 0, Math.pow(dt, 3) / 2, 0], [0, Math.pow(dt, 4) / 4, 0, Math.pow(dt, 3) / 2], [Math.pow(dt, 3) / 2, 0, Math.pow(dt, 2), 0], [0, Math.pow(dt, 3) / 2, 0, Math.pow(dt, 2)] ].map(row => row.map(val => val * 0.1)); // 噪声系数 // 预测状态 const x_pred = [ this.kalmanState.x + this.kalmanState.vx * dt, this.kalmanState.y + this.kalmanState.vy * dt, this.kalmanState.vx, this.kalmanState.vy ]; // 预测协方差 let P_pred = this._matrixMultiply(F, this.kalmanState.P); P_pred = this._matrixMultiply(P_pred, this._matrixTranspose(F)); P_pred = this._matrixAdd(P_pred, Q); // 测量矩阵 const H = [ [1, 0, 0, 0], [0, 1, 0, 0] ]; // 测量噪声协方差 const R = [ [Math.pow(newPoint.accuracy / 1000000, 2), 0], [0, Math.pow(newPoint.accuracy / 1000000, 2)] ]; // 卡尔曼增益 const S = this._matrixAdd( this._matrixMultiply(H, this._matrixMultiply(P_pred, this._matrixTranspose(H))), R ); const K = this._matrixMultiply( this._matrixMultiply(P_pred, this._matrixTranspose(H)), this._matrixInverse2x2(S) ); // 更新状态 const z = [newPoint.lng, newPoint.lat]; const y = [ z[0] - (H[0][0] * x_pred[0] + H[0][1] * x_pred[1] + H[0][2] * x_pred[2] + H[0][3] * x_pred[3]), z[1] - (H[1][0] * x_pred[0] + H[1][1] * x_pred[1] + H[1][2] * x_pred[2] + H[1][3] * x_pred[3]) ]; const x_upd = [ x_pred[0] + K[0][0] * y[0] + K[0][1] * y[1], x_pred[1] + K[1][0] * y[0] + K[1][1] * y[1], x_pred[2] + K[2][0] * y[0] + K[2][1] * y[1], x_pred[3] + K[3][0] * y[0] + K[3][1] * y[1] ]; // 更新协方差 const I = [ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1] ]; const KH = this._matrixMultiply(K, H); const I_KH = this._matrixSubtract(I, KH); const P_upd = this._matrixMultiply(I_KH, P_pred); // 更新状态 this.kalmanState = { x: x_upd[0], y: x_upd[1], vx: x_upd[2], vy: x_upd[3], P: P_upd, lastTime: newPoint.timestamp }; return { lng: x_upd[0], lat: x_upd[1], accuracy: newPoint.accuracy }; }, // 矩阵乘法 _matrixMultiply(A, B) { const result = []; for (let i = 0; i < A.length; i++) { result[i] = []; for (let j = 0; j < B[0].length; j++) { let sum = 0; for (let k = 0; k < A[0].length; k++) { sum += A[i][k] * B[k][j]; } result[i][j] = sum; } } return result; }, // 矩阵转置 _matrixTranspose(A) { return A[0].map((_, colIndex) => A.map(row => row[colIndex])); }, // 矩阵加法 _matrixAdd(A, B) { return A.map((row, i) => row.map((val, j) => val + B[i][j])); }, // 矩阵减法 _matrixSubtract(A, B) { return A.map((row, i) => row.map((val, j) => val - B[i][j])); }, // 2x2矩阵求逆 _matrixInverse2x2(A) { const det = A[0][0] * A[1][1] - A[0][1] * A[1][0]; return [ [A[1][1] / det, -A[0][1] / det], [-A[1][0] / det, A[0][0] / det] ]; }, // 开始平滑动画 _startAnimation(targetPoint) { // 取消之前的动画 if (this.animationTimer) { clearInterval(this.animationTimer); this.animationTimer = null; } // 设置目标位置 this.animationTarget = new T.LngLat(targetPoint.lng, targetPoint.lat); // 如果没有当前位置,直接设置 if (!this.currentPosition) { this.currentPosition = this.animationTarget; this._updateRealTimeMarker(targetPoint); return; } // 计算起点和终点 const startLng = this.currentPosition.getLng(); const startLat = this.currentPosition.getLat(); const endLng = this.animationTarget.getLng(); const endLat = this.animationTarget.getLat(); // 动画参数 const steps = Math.max(5, Math.min(20, this.animationDuration / 50)); const stepSize = 1 / steps; let progress = 0; // 启动动画 this.animationTimer = setInterval(() => { progress += stepSize; if (progress >= 1) { clearInterval(this.animationTimer); this.animationTimer = null; this.currentPosition = this.animationTarget; this._updateRealTimeMarker(targetPoint); // 定位点动画结束后,适配视野 // this._fitAllPoints(); return; } // 使用缓动函数使动画更平滑 const easedProgress = this._easeInOutCubic(progress); // 计算中间点 const currentLng = startLng + (endLng - startLng) * easedProgress; const currentLat = startLat + (endLat - startLat) * easedProgress; // 更新位置 this.currentPosition = new T.LngLat(currentLng, currentLat); this._updateRealTimeMarker({ lng: currentLng, lat: currentLat, accuracy: targetPoint.accuracy }); }, this.animationDuration / steps); }, // 缓动函数(三次缓动) _easeInOutCubic(t) { return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2; }, // 更新实时定位标记 // _updateRealTimeMarker(point) { // const mapPoint = new T.LngLat(point.lng, point.lat); // if (!this.realTimeMarker) { // // 创建标记 // this.realTimeMarker = new T.Marker(mapPoint); // this.Tmap.addOverLay(this.realTimeMarker); // // 创建文本标签 // this.realTimeLabel = new T.Label({ // // text: 实时定位:${point.lng.toFixed(6)},${point.lat.toFixed(6)}, // text: '实时定位', // position: mapPoint, // offset: new T.Point(-40, 10) // }); // this.Tmap.addOverLay(this.realTimeLabel); // } else { // // 更新位置 // this.realTimeMarker.setLngLat(mapPoint); // this.realTimeLabel.setLngLat(mapPoint); // // this.realTimeLabel.setLabel(实时定位:${point.lng.toFixed(6)},${point.lat.toFixed(6)}); // } // // 平滑移动地图中心 // // this.Tmap.panTo(mapPoint); // }, _fitAllPoints() { let points = []; // 点/线/面 if (this.gisData && this.gisPointLngLat) { if (this.gisData.type === 'marker') { points.push(new T.LngLat(this.gisPointLngLat.lng, this.gisPointLngLat.lat)); } else if (this.gisData.type === 'polyline' || this.gisData.type === 'polygon') { points = points.concat( this.gisPointLngLat.map(p => new T.LngLat(p.lng, p.lat)) ); } } // 当前定位点 if (this.currentPosition) { points.push(this.currentPosition); } // 过滤无效点 points = points.filter(p => p && typeof p.getLng === 'function' && typeof p.getLat === 'function'); if (points.length > 0) { this.Tmap.setViewport(points); } }, // 绘制地图元素(折线、多边形等) _drawMapElements() { if (!this.gisData || !this.gisPointLngLat) return; switch (this.gisData.type) { case 'marker': this._drawMarker(); break; case 'polyline': this._drawPolyline(); break; case 'polygon': this._drawPolygon(); break; } // 新增:绘制完后适配视野 this._fitAllPoints(); }, // 绘制标记点 _drawMarker() { const point = new T.LngLat(this.gisPointLngLat.lng, this.gisPointLngLat.lat); const marker = new T.Marker(point); this.Tmap.addOverLay(marker); const label = new T.Label({ text: this.gisData.name, position: point, offset: new T.Point(-40, 10) }); this.Tmap.addOverLay(label); }, // 绘制折线 _drawPolyline() { const points = this.gisPointLngLat.map(p => new T.LngLat(p.lng, p.lat) ); const polyline = new T.Polyline(points, { color: this.gisDataObj.color || '#FF0000', weight: 6, opacity: 0.7 }); this.Tmap.addOverLay(polyline); // 添加终点标签 const endPoint = points[points.length - 1]; const label = new T.Label({ text: this.gisData.name, position: endPoint, offset: new T.Point(-40, 10) }); this.Tmap.addOverLay(label); }, // 绘制多边形 _drawPolygon() { const points = this.gisPointLngLat.map(p => new T.LngLat(p.lng, p.lat) ); const polygon = new T.Polygon(points, { color: this.gisDataObj.color || '#1E90FF', weight: 3, fillColor: this.gisDataObj.color || '#1E90FF', fillOpacity: 0.3 }); this.Tmap.addOverLay(polygon); // 添加中心点标签 const center = this._calculateCenter(points); const label = new T.Label({ text: this.gisData.name, position: center, offset: new T.Point(-40, 10) }); this.Tmap.addOverLay(label); }, // 计算多边形中心点 _calculateCenter(points) { const sum = points.reduce((acc, point) => { acc.lng += point.getLng(); acc.lat += point.getLat(); return acc; }, { lng: 0, lat: 0 }); return new T.LngLat( sum.lng / points.length, sum.lat / points.length ); }, // RenderJS事件处理器 handleMessage(newVal, oldVal) { if (newVal !== oldVal && this.gisPointLngLat) { const geolocation = new T.Geolocation(); geolocation.getCurrentPosition(e => { const distance = this.getDistance( e.lnglat.lat, e.lnglat.lng, this.gisPointLngLat.lat, this.gisPointLngLat.lng ); this.$ownerInstance.callMethod('someMethodInVue', { lng: e.lnglat.lng, lat: e.lnglat.lat, distance: distance * 1000 }); }); } }, // 计算两点间距离(Haversine公式) getDistance(lat1, lng1, lat2, lng2) { const radLat1 = (lat1 * Math.PI) / 180.0; const radLat2 = (lat2 * Math.PI) / 180.0; const a = radLat1 - radLat2; const b = (lng1 * Math.PI) / 180.0 - (lng2 * Math.PI) / 180.0; const s = 2 * Math.asin( Math.sqrt( Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2) ) ); return s * 6378.137; // 返回公里数 }, // 初始化指南针 initCompass() { if (plus.orientation && plus.orientation.watchOrientation) { this.isCompassAvailable = true; this.compassWatchId = plus.orientation.watchOrientation( (orientation) => this._handleCompass(orientation), (err) => console.error('指南针错误:', err) ); } else { console.warn('设备不支持指南针功能'); this.isCompassAvailable = false; } }, // 处理指南针数据 _handleCompass(orientation) { const now = Date.now(); // 限制更新频率(100ms/次) if (now - this.lastHeadingUpdate < 100) return; this.lastHeadingUpdate = now; let heading = orientation.magneticHeading; // 平滑处理 if (this.currentHeading === undefined) { this.currentHeading = heading; } else { let diff = heading - this.currentHeading; if (diff > 180) diff -= 360; else if (diff < -180) diff += 360; this.currentHeading += diff * this.headingFilterFactor; if (this.currentHeading >= 360) this.currentHeading -= 360; else if (this.currentHeading < 0) this.currentHeading += 360; } // 更新标记方向 this._updateMarkerDirection(); }, // 更新标记方向 _updateMarkerDirection() { if (!this.realTimeMarker || this.currentHeading === undefined) return; // 检查是否需要更新 if (this.lastRenderedHeading === this.currentHeading) return; // 尝试从缓存获取 if (this.iconCache[this.currentHeading]) { this._setMarkerIcon(this.iconCache[this.currentHeading]); this.lastRenderedHeading = this.currentHeading; return; } // 动态生成旋转图标 this._generateRotatedIcon(this.currentHeading) .then(rotatedIcon => { this.iconCache[this.currentHeading] = rotatedIcon; this._setMarkerIcon(rotatedIcon); this.lastRenderedHeading = this.currentHeading; }); }, // 生成旋转后的图标 _generateRotatedIcon(heading) { return new Promise((resolve) => { const size = 30; const canvas = document.createElement('canvas'); canvas.width = size; canvas.height = size; const ctx = canvas.getContext('2d'); const img = new Image(); img.src = this.baseIcon; img.onload = () => { // 清除画布 ctx.clearRect(0, 0, size, size); // 移动到中心点 ctx.translate(size / 2, size / 2); // 旋转画布 ctx.rotate((heading * Math.PI) / 180); // 绘制图像(注意调整位置) ctx.drawImage(img, -size / 2, -size / 2, size, size); // 恢复画布状态 ctx.setTransform(1, 0, 0, 1, 0, 0); // 获取Base64数据 resolve(canvas.toDataURL('image/png')); }; }); }, // 设置标记图标 _setMarkerIcon(iconUrl) { if (!this.realTimeMarker) return; this.realTimeMarker.setIcon(new T.Icon({ iconUrl: iconUrl, iconSize: new T.Point(30, 30), className: 'direction-marker' })); }, // 在_updateRealTimeMarker中添加方向支持 _updateRealTimeMarker(point) { const mapPoint = new T.LngLat(point.lng, point.lat); if (!this.realTimeMarker) { // 使用基础图标创建标记 this.realTimeMarker = new T.Marker(mapPoint, { icon: new T.Icon({ iconUrl: this.baseIcon, iconSize: new T.Point(30, 30), className: 'direction-marker' }) }); this.Tmap.addOverLay(this.realTimeMarker); // 创建文本标签 this.realTimeLabel = new T.Label({ text: '实时定位', position: mapPoint, offset: new T.Point(-40, 10) }); this.Tmap.addOverLay(this.realTimeLabel); } else { // 更新位置 this.realTimeMarker.setLngLat(mapPoint); this.realTimeLabel.setLngLat(mapPoint); } // 如果支持指南针,更新方向 if (this.isCompassAvailable) { this._updateMarkerDirection(); } }, }, // 在组件销毁时清理 beforeDestroy() { // 清除位置监听 this._watchId && plus.geolocation.clearWatch(this._watchId); // 清除指南针监听 if (this.compassWatchId && plus.orientation.clearWatch) { plus.orientation.clearWatch(this.compassWatchId); } this.iconCache = {}; } }; </script> 第一,代码中的箭头不明显,我想要和高德百度类似的那种 第二,旋转不丝滑,一顿一顿的

#include "stm32g4xx_hal.h" #include "time.h" #include "main.h" #include "DCAC_ADC.h" #include "OLED.h" #include "adc.h" #include "math.h" #include "PID.h" #include "SPWM.h" #define ADC_SAMPLES 100 extern float Vcc; uint16_t volt[ADC_SAMPLES]; // DMA采集缓冲区 float V_value = 0.0f; // RMS值 float voltage ; // 平均电压 float Top; float PID_Top; float Sum_V_value=0; float target_votage; extern volatile uint8_t dma_complete_flag; // DMA完成标志 extern TIM_HandleTypeDef htim3; extern uint8_t Key_flag; float zhj_voltage; uint32_t adc_raw_value = 0; float voltage = 0.0f; // void Catch_start() { // ADC校准+DMA采集启动(只需一次) HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED); HAL_ADC_Start_DMA(&hadc1, (uint32_t*)volt, ADC_SAMPLES); HAL_TIM_Base_Start_IT(&htim3); } void Show_ADC1(float Move_value)//交流电压 { if(dma_complete_flag) { static uint16_t Sum_count = 0; // 静态变量保持状态 int32_t sum_rms = 0; for(int i = 0; i < ADC_SAMPLES; i++) { sum_rms += (volt[i]-(Move_value*1241))*(volt[i]-(Move_value*1241)); } //V_value = sqrt((float)sum_rms / ADC_SAMPLES); // 有效值(单位: ADC码) //滤波 Sum_V_value+=sqrt((float)sum_rms / ADC_SAMPLES); Sum_count++; if(Sum_count==35) { V_value=Sum_V_value/35; //最终ADC值 Sum_count=0; Sum_V_value=0; } // voltage = V_value* 3.3f / 4095.0f; // 真实值 Top=voltage*sqrtf(2); //当前值 target_votage=get_current_votage();//目标值 // 峰值 PID_Top=Buck_PID(target_votage,Top); // 增大单次调整限制和总输出限制 set_pwm(PID_Top); dma_complete_flag = 0; // 清除标志 // 重新启动DMA采集,循环模式不需要开启 // HAL_ADC_Start_DMA(&hadc1, (uint32_t*)volt, ADC_SAMPLES); } } void adc_read_and_display(void)//直流电压 { // 启动ADC转换 HAL_ADC_Start(&hadc2); // 等待转换完成(超时100ms) if (HAL_ADC_PollForConversion(&hadc2, 10) == HAL_OK) { // 读取原始ADC值(12位,范围0-4095) adc_raw_value = HAL_ADC_GetValue(&hadc2); // 转换为电压值(假设参考电压3.3V) zhj_voltage = (adc_raw_value * 3.3f) / 4095.0f; OLED_ShowString(1, 1, "Zhi_V:"); OLED_ShowString(4, 1, "Zhi_A:"); OLED_ShowString(2, 3, "Raw:"); OLED_ShowNum(2, 7, adc_raw_value, 4); // 显示4位原始值 // 在OLED上显示电压值(第2行,从第1列开始) OLED_ShowString(3, 3, "Volt:"); OLED_ShowNum(3, 8, (uint32_t)zhj_voltage, 1); // 整数部分 OLED_ShowString(3, 9, "."); OLED_ShowNum(3, 10, (uint32_t)(zhj_voltage * 1000) % 1000, 3); // 小数部分(毫伏级) OLED_ShowString(3, 13, "V"); } // 停止ADC转换 HAL_ADC_Stop(&hadc2); } 我的ADC2不工作/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file adc.c * @brief This file provides code for the configuration * of the ADC instances. ****************************************************************************** * @attention * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "adc.h" /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ ADC_HandleTypeDef hadc1; ADC_HandleTypeDef hadc2; DMA_HandleTypeDef hdma_adc1; /* ADC1 init function */ void MX_ADC1_Init(void) { /* USER CODE BEGIN ADC1_Init 0 */ /* USER CODE END ADC1_Init 0 */ ADC_MultiModeTypeDef multimode = {0}; ADC_ChannelConfTypeDef sConfig = {0}; /* USER CODE BEGIN ADC1_Init 1 */ /* USER CODE END ADC1_Init 1 */ /** Common config */ hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.GainCompensation = 0; hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; hadc1.Init.LowPowerAutoWait = DISABLE; hadc1.Init.ContinuousConvMode = ENABLE; hadc1.Init.NbrOfConversion = 1; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T3_TRGO; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; hadc1.Init.DMAContinuousRequests = ENABLE; hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED; hadc1.Init.OversamplingMode = DISABLE; if (HAL_ADC_Init(&hadc1) != HAL_OK) { Error_Handler(); } /** Configure the ADC multi-mode */ multimode.Mode = ADC_MODE_INDEPENDENT; if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_15; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_47CYCLES_5; sConfig.SingleDiff = ADC_SINGLE_ENDED; sConfig.OffsetNumber = ADC_OFFSET_NONE; sConfig.Offset = 0; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC1_Init 2 */ /* USER CODE END ADC1_Init 2 */ } /* ADC2 init function */ void MX_ADC2_Init(void) { /* USER CODE BEGIN ADC2_Init 0 */ /* USER CODE END ADC2_Init 0 */ ADC_ChannelConfTypeDef sConfig = {0}; /* USER CODE BEGIN ADC2_Init 1 */ /* USER CODE END ADC2_Init 1 */ /** Common config */ hadc2.Instance = ADC2; hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; hadc2.Init.Resolution = ADC_RESOLUTION_12B; hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc2.Init.GainCompensation = 0; hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE; hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV; hadc2.Init.LowPowerAutoWait = DISABLE; hadc2.Init.ContinuousConvMode = DISABLE; hadc2.Init.NbrOfConversion = 1; hadc2.Init.DiscontinuousConvMode = DISABLE; hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc2.Init.DMAContinuousRequests = DISABLE; hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED; hadc2.Init.OversamplingMode = DISABLE; if (HAL_ADC_Init(&hadc2) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_15; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5; sConfig.SingleDiff = ADC_SINGLE_ENDED; sConfig.OffsetNumber = ADC_OFFSET_NONE; sConfig.Offset = 0; if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC2_Init 2 */ /* USER CODE END ADC2_Init 2 */ } static uint32_t HAL_RCC_ADC12_CLK_ENABLED=0; void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; if(adcHandle->Instance==ADC1) { /* USER CODE BEGIN ADC1_MspInit 0 */ /* USER CODE END ADC1_MspInit 0 */ /** Initializes the peripherals clocks */ PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC12; PeriphClkInit.Adc12ClockSelection = RCC_ADC12CLKSOURCE_SYSCLK; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { Error_Handler(); } /* ADC1 clock enable */ HAL_RCC_ADC12_CLK_ENABLED++; if(HAL_RCC_ADC12_CLK_ENABLED==1){ __HAL_RCC_ADC12_CLK_ENABLE(); } __HAL_RCC_GPIOB_CLK_ENABLE(); /**ADC1 GPIO Configuration PB0 ------> ADC1_IN15 */ GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* ADC1 DMA Init */ /* ADC1 Init */ hdma_adc1.Instance = DMA1_Channel1; hdma_adc1.Init.Request = DMA_REQUEST_ADC1; hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE; hdma_adc1.Init.MemInc = DMA_MINC_ENABLE; hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; hdma_adc1.Init.Mode = DMA_CIRCULAR; hdma_adc1.Init.Priority = DMA_PRIORITY_LOW; if (HAL_DMA_Init(&hdma_adc1) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1); /* ADC1 interrupt Init */ HAL_NVIC_SetPriority(ADC1_2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(ADC1_2_IRQn); /* USER CODE BEGIN ADC1_MspInit 1 */ /* USER CODE END ADC1_MspInit 1 */ } else if(adcHandle->Instance==ADC2) { /* USER CODE BEGIN ADC2_MspInit 0 */ /* USER CODE END ADC2_MspInit 0 */ /** Initializes the peripherals clocks */ PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC12; PeriphClkInit.Adc12ClockSelection = RCC_ADC12CLKSOURCE_SYSCLK; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { Error_Handler(); } /* ADC2 clock enable */ HAL_RCC_ADC12_CLK_ENABLED++; if(HAL_RCC_ADC12_CLK_ENABLED==1){ __HAL_RCC_ADC12_CLK_ENABLE(); } __HAL_RCC_GPIOB_CLK_ENABLE(); /**ADC2 GPIO Configuration PB15 ------> ADC2_IN15 */ GPIO_InitStruct.Pin = GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* ADC2 interrupt Init */ HAL_NVIC_SetPriority(ADC1_2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(ADC1_2_IRQn); /* USER CODE BEGIN ADC2_MspInit 1 */ /* USER CODE END ADC2_MspInit 1 */ } } void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle) { if(adcHandle->Instance==ADC1) { /* USER CODE BEGIN ADC1_MspDeInit 0 */ /* USER CODE END ADC1_MspDeInit 0 */ /* Peripheral clock disable */ HAL_RCC_ADC12_CLK_ENABLED--; if(HAL_RCC_ADC12_CLK_ENABLED==0){ __HAL_RCC_ADC12_CLK_DISABLE(); } /**ADC1 GPIO Configuration PB0 ------> ADC1_IN15 */ HAL_GPIO_DeInit(GPIOB, GPIO_PIN_0); /* ADC1 DMA DeInit */ HAL_DMA_DeInit(adcHandle->DMA_Handle); /* ADC1 interrupt Deinit */ /* USER CODE BEGIN ADC1:ADC1_2_IRQn disable */ /** * Uncomment the line below to disable the "ADC1_2_IRQn" interrupt * Be aware, disabling shared interrupt may affect other IPs */ /* HAL_NVIC_DisableIRQ(ADC1_2_IRQn); */ /* USER CODE END ADC1:ADC1_2_IRQn disable */ /* USER CODE BEGIN ADC1_MspDeInit 1 */ /* USER CODE END ADC1_MspDeInit 1 */ } else if(adcHandle->Instance==ADC2) { /* USER CODE BEGIN ADC2_MspDeInit 0 */ /* USER CODE END ADC2_MspDeInit 0 */ /* Peripheral clock disable */ HAL_RCC_ADC12_CLK_ENABLED--; if(HAL_RCC_ADC12_CLK_ENABLED==0){ __HAL_RCC_ADC12_CLK_DISABLE(); } /**ADC2 GPIO Configuration PB15 ------> ADC2_IN15 */ HAL_GPIO_DeInit(GPIOB, GPIO_PIN_15); /* ADC2 interrupt Deinit */ /* USER CODE BEGIN ADC2:ADC1_2_IRQn disable */ /** * Uncomment the line below to disable the "ADC1_2_IRQn" interrupt * Be aware, disabling shared interrupt may affect other IPs */ /* HAL_NVIC_DisableIRQ(ADC1_2_IRQn); */ /* USER CODE END ADC2:ADC1_2_IRQn disable */ /* USER CODE BEGIN ADC2_MspDeInit 1 */ /* USER CODE END ADC2_MspDeInit 1 */ } } /* USER CODE BEGIN 1 */ // hdma_adc1.Init.Mode = DMA_CIRCULAR;---------136�� /* USER CODE END 1 */

大家在看

recommend-type

商品条形码及生产日期识别数据集

商品条形码及生产日期识别数据集,数据集样本数量为2156,所有图片已标注为YOLO txt格式,划分为训练集、验证集和测试集,能直接用于YOLO算法的训练。可用于跟本识别目标相关的蓝桥杯比赛项目
recommend-type

7.0 root.rar

Android 7.0 MTK MT8167 user 版本root权限修改,super权限修改,当第三方APP想要获取root权限时,会弹出窗口访问是否给与改APP root权限,同意后该APP可以得到root权限,并操作相关内容
recommend-type

RK3308开发资料

RK3308全套资料,《06 RK3308 硬件设计介绍》《07 RK3308 软件方案介绍》《08 RK3308 Audio开发介绍》《09 RK3308 WIFI-BT功能及开发介绍》
recommend-type

即时记截图精灵 v2.00.rar

即时记截图精灵是一款方便易用,功能强大的专业截图软件。   软件当前版本提供以下功能:   1. 可以通过鼠标选择截图区域,选择区域后仍可通过鼠标进行边缘拉动或拖拽来调整所选区域的大小和位置。   2. 可以将截图复制到剪切板,或者保存为图片文件,或者自动打开windows画图程序进行编辑。   3. 保存文件支持bmp,jpg,png,gif和tif等图片类型。   4. 新增新浪分享按钮。
recommend-type

WinUSB4NuVCOM_NUC970+NuWriter.rar

NUC970 USB启动所需的USB驱动,已经下载工具NuWriter,可以用于裸机启动NUC970调试,将USB接电脑后需要先安装WinUSB4NuVCOM_NUC970驱动,然后使用NuWriter初始化硬件,之后就可以使用jlink或者ulink调试。

最新推荐

recommend-type

C#类库封装:简化SDK调用实现多功能集成,构建地磅无人值守系统

内容概要:本文介绍了利用C#类库封装多个硬件设备的SDK接口,实现一系列复杂功能的一键式调用。具体功能包括身份证信息读取、人证识别、车牌识别(支持臻识和海康摄像头)、LED显示屏文字输出、称重数据读取、二维码扫描以及语音播报。所有功能均被封装为简单的API,极大降低了开发者的工作量和技术门槛。文中详细展示了各个功能的具体实现方式及其应用场景,如身份证读取、人证核验、车牌识别等,并最终将这些功能整合到一起,形成了一套完整的地磅称重无人值守系统解决方案。 适合人群:具有一定C#编程经验的技术人员,尤其是需要快速集成多种硬件设备SDK的应用开发者。 使用场景及目标:适用于需要高效集成多种硬件设备SDK的项目,特别是那些涉及身份验证、车辆管理、物流仓储等领域的企业级应用。通过使用这些封装好的API,可以大大缩短开发周期,降低维护成本,提高系统的稳定性和易用性。 其他说明:虽然封装后的API极大地简化了开发流程,但对于一些特殊的业务需求,仍然可能需要深入研究底层SDK。此外,在实际部署过程中,还需考虑网络环境、硬件兼容性等因素的影响。
recommend-type

基于STM32F1的BLDC无刷直流电机与PMSM永磁同步电机源码解析:传感器与无传感器驱动详解

基于STM32F1的BLDC无刷直流电机和PMSM永磁同步电机的驱动实现方法,涵盖了有传感器和无传感两种驱动方式。对于BLDC电机,有传感器部分采用霍尔传感器进行六步换相,无传感部分则利用反电动势过零点检测实现换相。对于PMSM电机,有传感器部分包括霍尔传感器和编码器的方式,无传感部分则采用了滑模观测器进行矢量控制(FOC)。文中不仅提供了详细的代码片段,还分享了许多调试经验和技巧。 适合人群:具有一定嵌入式系统和电机控制基础知识的研发人员和技术爱好者。 使用场景及目标:适用于需要深入了解和实现BLDC和PMSM电机驱动的开发者,帮助他们掌握不同传感器条件下的电机控制技术和优化方法。 其他说明:文章强调了实际调试过程中可能遇到的问题及其解决方案,如霍尔传感器的中断触发换相、反电动势过零点检测的采样时机、滑模观测器的参数调整以及编码器的ABZ解码等。
recommend-type

基于Java的跨平台图像处理软件ImageJ:多功能图像编辑与分析工具

内容概要:本文介绍了基于Java的图像处理软件ImageJ,详细阐述了它的跨平台特性、多线程处理能力及其丰富的图像处理功能。ImageJ由美国国立卫生研究院开发,能够在多种操作系统上运行,包括Windows、Mac OS、Linux等。它支持多种图像格式,如TIFF、PNG、GIF、JPEG、BMP、DICOM、FITS等,并提供图像栈功能,允许多个图像在同一窗口中进行并行处理。此外,ImageJ还提供了诸如缩放、旋转、扭曲、平滑处理等基本操作,以及区域和像素统计、间距、角度计算等高级功能。这些特性使ImageJ成为科研、医学、生物等多个领域的理想选择。 适合人群:需要进行图像处理的专业人士,如科研人员、医生、生物学家,以及对图像处理感兴趣的普通用户。 使用场景及目标:适用于需要高效处理大量图像数据的场合,特别是在科研、医学、生物学等领域。用户可以通过ImageJ进行图像的编辑、分析、处理和保存,提高工作效率。 其他说明:ImageJ不仅功能强大,而且操作简单,用户无需安装额外的运行环境即可直接使用。其基于Java的开发方式确保了不同操作系统之间的兼容性和一致性。
recommend-type

MATLAB语音识别系统:基于GUI的数字0-9识别及深度学习模型应用 · GUI v1.2

内容概要:本文介绍了一款基于MATLAB的语音识别系统,主要功能是识别数字0到9。该系统采用图形用户界面(GUI),方便用户操作,并配有详尽的代码注释和开发报告。文中详细描述了系统的各个组成部分,包括音频采集、信号处理、特征提取、模型训练和预测等关键环节。此外,还讨论了MATLAB在此项目中的优势及其面临的挑战,如提高识别率和处理背景噪音等问题。最后,通过对各模块的工作原理和技术细节的总结,为未来的研究和发展提供了宝贵的参考资料。 适合人群:对语音识别技术和MATLAB感兴趣的初学者、学生或研究人员。 使用场景及目标:适用于希望深入了解语音识别技术原理的人群,特别是希望通过实际案例掌握MATLAB编程技巧的学习者。目标是在实践中学习如何构建简单的语音识别应用程序。 其他说明:该程序需要MATLAB 2019b及以上版本才能正常运行,建议使用者确保软件环境符合要求。
recommend-type

Teleport Pro教程:轻松复制网站内容

标题中提到的“复制别人网站的软件”指向的是一种能够下载整个网站或者网站的特定部分,然后在本地或者另一个服务器上重建该网站的技术或工具。这类软件通常被称作网站克隆工具或者网站镜像工具。 描述中提到了一个具体的教程网址,并提到了“天天给力信誉店”,这可能意味着有相关的教程或资源可以在这个网店中获取。但是这里并没有提供实际的教程内容,仅给出了网店的链接。需要注意的是,根据互联网法律法规,复制他人网站内容并用于自己的商业目的可能构成侵权,因此在此类工具的使用中需要谨慎,并确保遵守相关法律法规。 标签“复制 别人 网站 软件”明确指出了这个工具的主要功能,即复制他人网站的软件。 文件名称列表中列出了“Teleport Pro”,这是一款具体的网站下载工具。Teleport Pro是由Tennyson Maxwell公司开发的网站镜像工具,允许用户下载一个网站的本地副本,包括HTML页面、图片和其他资源文件。用户可以通过指定开始的URL,并设置各种选项来决定下载网站的哪些部分。该工具能够帮助开发者、设计师或内容分析人员在没有互联网连接的情况下对网站进行离线浏览和分析。 从知识点的角度来看,Teleport Pro作为一个网站克隆工具,具备以下功能和知识点: 1. 网站下载:Teleport Pro可以下载整个网站或特定网页。用户可以设定下载的深度,例如仅下载首页及其链接的页面,或者下载所有可访问的页面。 2. 断点续传:如果在下载过程中发生中断,Teleport Pro可以从中断的地方继续下载,无需重新开始。 3. 过滤器设置:用户可以根据特定的规则过滤下载内容,如排除某些文件类型或域名。 4. 网站结构分析:Teleport Pro可以分析网站的链接结构,并允许用户查看网站的结构图。 5. 自定义下载:用户可以自定义下载任务,例如仅下载图片、视频或其他特定类型的文件。 6. 多任务处理:Teleport Pro支持多线程下载,用户可以同时启动多个下载任务来提高效率。 7. 编辑和管理下载内容:Teleport Pro具备编辑网站镜像的能力,并可以查看、修改下载的文件。 8. 离线浏览:下载的网站可以在离线状态下浏览,这对于需要测试网站在不同环境下的表现的情况十分有用。 9. 备份功能:Teleport Pro可以用来备份网站,确保重要数据的安全。 在实际使用此类工具时,需要注意以下几点: - 著作权法:复制网站内容可能侵犯原作者的版权,因此在使用此类工具时,必须确保有合法权利去下载和使用目标网站的内容。 - 服务条款:许多网站的服务条款明确禁止未经授权的网站克隆。因此,在使用此类软件之前,应当仔细阅读并遵守目标网站的服务条款。 - 数据隐私:下载含有个人数据的网站可能触及隐私保护法律,特别是在欧洲通用数据保护条例(GDPR)等法规的环境下。 - 网络安全:随意下载网站可能导致恶意软件和病毒的传播,用户应当使用最新的反病毒软件,并在安全的环境中进行操作。 综上所述,虽然“复制别人网站的软件”在技术上是可行的,且可以用于多种正当目的,但在使用此类工具时,必须遵守法律法规和道德规范,不可侵犯他人的合法权益。
recommend-type

【跨平台开发者的必读】:解决Qt5Widgetsd.lib目标计算机类型冲突终极指南

# 1. 跨平台开发与Qt框架简介 跨平台开发已经成为现代软件开发中不可或缺的一部分,它使得开发者能够构建出能够在多种操作系统上运行的应用程序,从而触及更广泛的用户群体。在这其中,Qt框架作为一套成熟的跨平台应用程序和用户界面框架,扮演着关键角色。Qt不仅仅是一个跨平台的工具集,它的设计哲学还包含了模块化和可扩展性,使其能够适应各种规模和复杂度的项目。本章节我们将简要介绍
recommend-type

普通RNN结构和特点

<think>首先,用户的问题是:“我想了解普通RNN的结构及其特点请问RNN循环神经网络结构特点工作原理”。这涉及到RNN的结构、特点和工作原理。根据系统级指令:-所有行内数学表达式必须使用$...$格式。-独立公式必须使用$$...$$格式并单独成段。-LaTeX语法正确。-使用中文回答。-生成相关问题。-回答中引用的段落末尾自然地添加引用标识。用户可见层指令:-回答结构清晰,帮助用户逐步解决问题。-保证回答真实可靠。参考站内引用:-引用[1]:关于RNN的基本介绍,为什么需要RNN。-引用[2]:关于RNN的工作原理、结构图,以及与其他网络的比较。用户上一次的问题和我的回答:用户是第一次
recommend-type

探讨通用数据连接池的核心机制与应用

根据给定的信息,我们能够推断出讨论的主题是“通用数据连接池”,这是一个在软件开发和数据库管理中经常用到的重要概念。在这个主题下,我们可以详细阐述以下几个知识点: 1. **连接池的定义**: 连接池是一种用于管理数据库连接的技术,通过维护一定数量的数据库连接,使得连接的创建和销毁操作更加高效。开发者可以在应用程序启动时预先创建一定数量的连接,并将它们保存在一个池中,当需要数据库连接时,可以直接从池中获取,从而降低数据库连接的开销。 2. **通用数据连接池的概念**: 当提到“通用数据连接池”时,它意味着这种连接池不仅支持单一类型的数据库(如MySQL、Oracle等),而且能够适应多种不同数据库系统。设计一个通用的数据连接池通常需要抽象出一套通用的接口和协议,使得连接池可以兼容不同的数据库驱动和连接方式。 3. **连接池的优点**: - **提升性能**:由于数据库连接创建是一个耗时的操作,连接池能够减少应用程序建立新连接的时间,从而提高性能。 - **资源复用**:数据库连接是昂贵的资源,通过连接池,可以最大化现有连接的使用,避免了连接频繁创建和销毁导致的资源浪费。 - **控制并发连接数**:连接池可以限制对数据库的并发访问,防止过载,确保数据库系统的稳定运行。 4. **连接池的关键参数**: - **最大连接数**:池中能够创建的最大连接数。 - **最小空闲连接数**:池中保持的最小空闲连接数,以应对突发的连接请求。 - **连接超时时间**:连接在池中保持空闲的最大时间。 - **事务处理**:连接池需要能够管理不同事务的上下文,保证事务的正确执行。 5. **实现通用数据连接池的挑战**: 实现一个通用的连接池需要考虑到不同数据库的连接协议和操作差异。例如,不同的数据库可能有不同的SQL方言、认证机制、连接属性设置等。因此,通用连接池需要能够提供足够的灵活性,允许用户配置特定数据库的参数。 6. **数据连接池的应用场景**: - **Web应用**:在Web应用中,为了处理大量的用户请求,数据库连接池可以保证数据库连接的快速复用。 - **批处理应用**:在需要大量读写数据库的批处理作业中,连接池有助于提高整体作业的效率。 - **微服务架构**:在微服务架构中,每个服务可能都需要与数据库进行交互,通用连接池能够帮助简化服务的数据库连接管理。 7. **常见的通用数据连接池技术**: - **Apache DBCP**:Apache的一个Java数据库连接池库。 - **C3P0**:一个提供数据库连接池和控制工具的开源Java框架。 - **HikariCP**:目前性能最好的开源Java数据库连接池之一。 - **BoneCP**:一个高性能的开源Java数据库连接池。 - **Druid**:阿里巴巴开源的一个数据库连接池,提供了对性能监控的高级特性。 8. **连接池的管理与监控**: 为了保证连接池的稳定运行,开发者需要对连接池的状态进行监控,并对其进行适当的管理。监控指标可能包括当前活动的连接数、空闲的连接数、等待获取连接的请求队列长度等。一些连接池提供了监控工具或与监控系统集成的能力。 9. **连接池的配置和优化**: 连接池的性能与连接池的配置密切相关。需要根据实际的应用负载和数据库性能来调整连接池的参数。例如,在高并发的场景下,可能需要增加连接池中连接的数量。另外,适当的线程池策略也可以帮助连接池更好地服务于多线程环境。 10. **连接池的应用案例**: 一个典型的案例是电商平台在大型促销活动期间,用户访问量激增,此时通用数据连接池能够保证数据库操作的快速响应,减少因数据库连接问题导致的系统瓶颈。 总结来说,通用数据连接池是现代软件架构中的重要组件,它通过提供高效的数据库连接管理,增强了软件系统的性能和稳定性。了解和掌握连接池的原理及实践,对于任何涉及数据库交互的应用开发都至关重要。在实现和应用连接池时,需要关注其设计的通用性、配置的合理性以及管理的有效性,确保在不同的应用场景下都能发挥出最大的效能。
recommend-type

【LabVIEW网络通讯终极指南】:7个技巧提升UDP性能和安全性

# 摘要 本文系统介绍了LabVIEW在网络通讯中的应用,尤其是针对UDP协议的研究与优化。首先,阐述了UDP的原理、特点及其在LabVIEW中的基础应用。随后,本文深入探讨了通过调整数据包大小、实现并发通信及优化缓冲区管理等技巧来优化UDP性能的LabVIEW方法。接着,文章聚焦于提升UDP通信安全性,介绍了加密技术和认证授权机制在LabVIEW中的实现,以及防御网络攻击的策略。最后,通过具体案例展示了LabVIEW在实时数据采集和远程控制系统中的高级应用,并展望了LabVIEW与UDP通讯技术的未来发展趋势及新兴技术的影响。 # 关键字 LabVIEW;UDP网络通讯;性能优化;安全性;
recommend-type

简要介绍cnn卷积神经网络

<think>首先,用户的问题是:“我想了解卷积神经网络的基本概念和原理 请问CNN卷积神经网络简介及其工作原理”。所以,我需要基于提供的引用材料,构建一个清晰的回答。 引用材料总结: - [^1]: CNN的核心思想是局部感受野、权值共享和时间或空间亚采样,提供位移、尺度、形变不变性。三大特色:局部感知、权重共享和多卷积核。 - [^2]: CNN是一种前馈神经网络,由卷积层和池化层组成,特别在图像处理方面出色。与传统多层神经网络相比,CNN加入了卷积层和池化层,使特征学习更有效。 - [^3]: CNN与全连接神经网络的区别:至少有一个卷积层提取特征;神经元局部连接和权值共享,减少参数数