基于开源ATmega8 无感BLDC程序移植到ATmega328PB

news2025/3/16 16:17:23

基于开源ATmega8 无感BLDC程序移植到ATmega328PB


  • 🔖基于Atmel Studio 7.0开发环境。
  • 🥕开源原项目资源地址:https://svn.mikrokopter.de/websvn/listing.php?repname=BL-Ctrl&path=%2F&
  • 📍原理图和PCB资源 BL-Ctrl v2.0 in Eagle(MEGA168与本移植项目原理图差异较大):https://github.com/Janesak1977/BLCTRL20_HW
  • 🌿BL-Ctrl官网BL-Ctrl V3、BL-Ctrl V2.0、BL-Ctrl V1.2资料介绍:https://wiki.mikrokopter.de/en/BL-Ctrl?action=show&redirect=en%2FBrushlessCtrl
  • 📜BL-Ctrl历史版本查询:https://wiki.mikrokopter.de/Ctrl_History

ATmega8 单片机和ATmega328PB差异不大,大部分寄存器无需修改,少数寄存器存在差异,硬件资源上,ATmega328PB资源外设比ATmega8多,价格上差不多。虽然采用的是8位单片机,与当今主流单片机,在性能上无法比拟。不影响学习研究。

  • ✨同驱动类型,性价比更高的,国内开源公开资料的有:基于STC8和STC32单片机梁工的相关无刷电机驱动工程,可从STCAI论坛获取相关资料。原理实现方法相同,应该也算是借鉴过来的,后起之作。
  • 📍STC梁工开源的三相无刷直流电机驱动资料地址:https://www.stcaimcu.com/forum.php?mod=viewthread&tid=1822&highlight=%E6%97%A0%E5%88%B7%E7%94%B5%E6%9C%BA&page=1&extra=#pid11784
  • 🎉此项目开源,同类型驱动控制里面,在当时算得上最早被公开的了。里面的部分经典算法一直被同类型驱动上所采用。
  • 📜按照此开源资料,如果想移植到其它单片机上,按照此反电动势检测实现方法,硬件要求是需要有一个模拟比较器。和需要能产生3路PWM信号来驱动H桥,这最基本的电机转动的要求。如果还需要电流采集以及ADC调速,那就需要单片机要有ADC资源。
  • 🌿早期相关ATmega328P相关移植参考文章:https://www.amobbs.com/thread-4652868-1-1.html
  • 🌼移植后基于自制驱动板,驱动转动效果:
    🌼
  • 📌自制驱动板相关内容《自制无感无刷电机驱动板》
  • ✒自己亲手移植一遍工程,不是简单的照搬一次代码,起码对整个无感无刷电机运转实现,有一个认识和了解,同时硬件上学习了2个单片机的资源外设,进行熟悉了一遍。
  • 🌿ATmega8 原理图:https://wiki.mikrokopter.de/en/BL-Ctrl_V1.2
    在这里插入图片描述
  • 🌿通过上面的BL-Ctrl_V1.2版本原理图移植到ATmega328PB,个人使用参考的源码是:V0.42:https://svn.mikrokopter.de/websvn/listing.php?repname=BL-Ctrl&path=%2Ftags%2FV0.42%2F&#a4bfcc0886576e3118d94460220fa558a
    在这里插入图片描述
  • 🌿ATmega328PB引脚连接参考上面的图纸:BL-Ctrl_V1.2版本原理图。相关1.2版本程序:https://github.com/jankae/brushlessControl
  • 🔨代码移植编译平台:Atmel Studio 7.0

⛳移植难点和重点

✨整个工程,基本都是围绕着,电机转动时,反电动势检测过零点内容的实现。对于PWM发波,都是比较容易配置和实现的。
  • 🌟ATmega8 和ATmega328PB自带的模拟比较器功能又和ADC功能相关寄存器共生,不能同时启用,导致需要功能切换时,需要及时改变相关寄存器位的配置。
📑基于反电动势检测过零点有两种方式:
  • 🥕基于 ADC 采样的无感方波电机控制 ADC 采样检测过零点。

  • 🥕基于比较器检测的无感方波电机控制 比较器检测过零点。(本项目采用的方式)

    • 🍁比较器检测过零点电路部分:

在这里插入图片描述

  • 📐理论计算和推导部分:
    在这里插入图片描述

📙移植到ATmega328PB,相关寄存器变更

  • 🌿外部时钟频率原来的8MHz换成16MHz。
  • 🌿TCCR2对应ATmega328PB相关寄存器TCCR0ATCCR0B
  • 🌿SFIOR对应ATmega328PB相关寄存器ADCSRB
  • 🌿参考电压差异,ATmega8 内部参考电压:2.56v,而ATmega328PB内部参考电压:1.1V。(个人移植使用的是AVCC作为参考电压即5V)
  • ✨在移植程序中需要处理的个别寄存器位差异,需要调整的地方比较多,如果自己移植,哪里报错有问题改哪里。

🛠3路PWM控制上桥臂说明

  • 🌿3路PWM控制上桥臂的信号频率个人采用的是15.625KHz.
  • 🌿引脚分别是:PB1、PB2、PB3
  • 🌿定时器通道选择和使用:
PB1  OC1A(定时器1,通道A)	 Mode: Normal top=0xFF
PB2  OC1B(定时器1,通道B)	 Mode: Normal top=0xFF
PB3  OC2A(定时器2,通道A)	 Mode: Normal top=0xFF
  • 🔧3路控制PWM信号核心代码:
#define PWM_A_ON  {TCCR1A=(1<<WGM10);TCCR1B=(1<<WGM12)| (1<<CS12) |(1<<CS10);TCCR2A=(1<<COM2A1)|(1<<WGM21) | (1<<WGM20);TCCR2B=(1<<CS22) | (1<<CS21) | (1<<CS20);  DDRB = 0x08;}//PB3

#define PWM_B_ON  {	TCCR1A =  (1<<COM1B1) | (1<<WGM10);TCCR1B= (1<<WGM12)|(1<<CS12)|(1<<CS10);TCCR2A= (1<<WGM21) | (1<<WGM20) ;TCCR2B=(1<<CS22) | (1<<CS21) | (1<<CS20); DDRB = (1<<DDB2);}//PB2

#define PWM_C_ON  {TCCR1A = (1<<COM1A1)|(1<<WGM10);TCCR1B=(1<<WGM12) |  (1<<CS12)|(1<<CS10);TCCR2A =(1<<WGM21)|(1<<WGM20);TCCR2B=  (1<<CS22) | (1<<CS21) | (1<<CS20); DDRB = (1<<DDB1);}//PB1
  • 🔑双路同时输出方式:
#define PWM_C_ON  {TCCR1A = (1<<COM1A1)|(1<<WGM10);TCCR1B=(1<<CS12);TCCR1C=(1<<FOC1A)|(1<<FOC1B);TCCR2A= (1<<WGM21)|(1<<WGM20);TCCR2B =(1<<FOC2A)|(1<<CS21);DDRB = 0x0A;}//PB3 ->OC2A	;PB1 ->OC1A	clkI/O/8
#define PWM_B_ON  {TCCR1A = (1<<COM1B1)|(1<<WGM10);TCCR1B=(1<<CS12);TCCR1C=(1<<FOC1A)|(1<<FOC1B); TCCR2A=(1<<COM2A1)|(1<<WGM21)|(1<<WGM20);TCCR2B =(1<<FOC2A)|(1<<CS21);DDRB = 0x0C;}//PB3 ->OC2A ; PB2 ->OC1B
#define PWM_A_ON  {TCCR1A =(1<<WGM10);TCCR1B=(1<<CS12);TCCR1C=(1<<FOC1A)|(1<<FOC1B);TCCR2A= (1<<COM2A1)|(1<<WGM21)|(1<<WGM20);TCCR2B = (1<<FOC2A)|(1<<CS21);DDRB = 0x08;}//PB3 ->OC2A
#define PWM_OFF   {TCCR1B &=~((1<<CS10)|(1<<CS11)|(1<<CS12));TCCR2B &=~((1<<CS20)|(1<<CS21)|(1<<CS22));PORTB &= ~0x0E;}

双路输出模式下,PWM_B_ON PWM_A_ON ,寄存器TCCR2A可以都配置定时器2的通道 A 的比较输出模式(1<<COM2A1),或者两者配置其一。推荐这两项控制,仅配置PWM_C_ON,其它参数不变的情况下,测试明显电流要小一些。

📘3路下桥臂采用IO开关控制

#define  STEUER_A_L {PORTD &= ~0x30; PORTD |= 0x08;}//U- ->PD3
#define  STEUER_B_L {PORTD &= ~0x28; PORTD |= 0x10;}//V- ->PD4
#define  STEUER_C_L {PORTD &= ~0x18; PORTD |= 0x20;}//W- ->PD5
  • 🔖以下内容待写……

📙ADC检测

  • 🔖ADC采集电流,是通过硬件蛇形布线实现的。具体看开源资料中的PCB文件。
    在这里插入图片描述
  • 📑ADC采集代码实现,进行ADC功能前,需要关闭模拟比较器,采集完ADC数据后,需要打开模拟比较器。两个不能同时启用。
//############################################################################
//Strom Analogwerte lesen
unsigned int MessAD(unsigned char channel)
//############################################################################
{
    unsigned char sense;
    sense = ADMUX;   // Sense-Kanal merken
    channel |= IntRef;
    ADMUX  =  channel;  // 开启对应ADC通道
    //SFIOR  =  0x00;  // Analog Comperator aus
    ADCSRB &= ~(1<<ACME);//关闭模拟比较器
//    GTCCR &=~((1<<PSRSYNC)|(1<<PSRASY));//将定时器2,0,1,3,4分频系数reset
//    MCUCR  &=~(1<<PUD);//禁用上拉电阻
//  ADC is enabled
    PRR0&= ~(1<<PRADC);
    ADMUX  =  channel;  //
    /*
     * initialize ADC:
     * Prescaler = 16 -> 1MHz,
     * Enable + Start
     */
    ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADPS2);
//等待转换完成
    while(ADCSRA & (0x01 << ADIF));    /* check if ADC conversion complete */
//   while (ADCSRA & (1 << ADSC));// wait for ADC to finish
    ADCSRA = 0x00;

    ADMUX = sense;   // zurück auf den Sense-Kanal
//   SFIOR = 0x08;  // Analog Comperator ein

    ADCSRB |= (1<<ACME);//打开模拟比较器
// ADC is disabled to preserve power
//    PRR0|= 1<<PRADC;
    ADCSRB |= (1<<ACME);//当ACME为1,且ADEN为0时可以选择ADC相关引脚为负输入
    ADCSRA &= ~_BV(ADEN);
    /*
    Bit 3 – ACIE Analog Comparator Interrupt Enable
    Bit 6 – ACBG Analog Comparator Bandgap Select
    */
    ACSR |= _BV(ACIE);
    ACSR &= ~_BV(ACBG);//当该位被清除时,AIN0被应用于模拟比较器的正输入。
//    GTCCR &=~((1<<PSRSYNC)|(1<<PSRASY));//将定时器2,0,1,3,4分频系数reset
    MCUCR  &=~(1<<PUD);//禁用上拉电阻

    return (ADCW);
}

📗三相反电动势检测比较器实现。

  • 📄三相反电动势检测,对应电机转动过程就的:消磁事件,过零事件,换相事件。(下面参考图来源于网络)
    在这里插入图片描述

🧲电机启动实现方式

  • 📝强制启动,代码实现:
//############################################################################
//电机启动
char Anwerfen(unsigned char pwm)
//############################################################################
{
    unsigned long timer = 200, i;//timer = 300
    DISABLE_SENSE_INT;//关闭模拟比较器中断
    PWM = 16;
    SetPWM();//T1和T2定时计数器赋值,设置pwm占空比
    /*补充注释:
    开环顺序换向算法,注意换向时必须同步修改比较器端口及触发沿
    以便在反相感生电动势到达切换条件时,自动切换到闭环运转状态
    */
    Manuell();//换相操作
    Delay_ms(200);
    /*
        MinUpmPulse = SetDelay(300);
        while (!CheckDelay(MinUpmPulse))
        {
            FastADConvert();
            if (Strom > 120)
            {
                STEUER_OFF; // 因短路而关闭
                RotBlink(10);
                printf("ADC7 Strom STOP\r\n");
                return (0);
            }
        }
    	*/
    PWM = pwm;

    while (1)
    {
        /*
                for (i = 0; i < timer; i++)
                {
                    if (!UebertragungAbgeschlossen)  SendUart();
                    else DatenUebertragung();
                    //  Wait(100);  // warten 8/8
                    Wait(25);//328p 16/64
                }
                DebugAusgaben();
                FastADConvert();
                if (Strom > 60)
                {
                    STEUER_OFF; // Abschalten wegen Kurzschluss
                    RotBlink(10);
                    return (0);
                }
        */
        timer -= timer / 15 + 1;
        if (timer < 25)
        {
            if (TEST_MANUELL) timer = 25;
            else return (1);
        }
        Manuell();//BLDC换相
        Phase++;
        Phase %= 6;
        AdConvert();
        PWM = pwm;
        SetPWM();
        if (SENSE)
        {
            PORTD ^= GRUEN;
        }
    }
}

//############################################################################
/*
开环顺序换向算法,注意换向时必须同步修改比较器端口及触发沿
以便在反相感生电动势到达切换条件时,自动切换到闭环运转状态
*/
void Manuell(void)//BLDC换相
//############################################################################
{
    switch (Phase)
    {
    case 0:
        STEUER_A_H;//U+
        STEUER_B_L;//V-
        SENSE_C;//比较器选择,通道 ADC2(PC2)作为负输入端
        SENSE_RISING_INT;//模拟比较器输出的上升沿产生中断
        break;
    case 1:
        STEUER_A_H;
        STEUER_C_L;
        SENSE_B;//比较器选择,通道 ADC1(PC1)作为负输入端
        SENSE_FALLING_INT;
        break;
    case 2:
        STEUER_B_H;
        STEUER_C_L;
        SENSE_A;//比较器选择,通道 ADC1(PC0)作为负输入端
        SENSE_RISING_INT;
        break;
    case 3:
        STEUER_B_H;
        STEUER_A_L;
        SENSE_C;
        SENSE_FALLING_INT;
        break;
    case 4:
        STEUER_C_H;
        STEUER_A_L;
        SENSE_B;
        SENSE_RISING_INT;
        break;
    case 5:
        STEUER_C_H;
        STEUER_B_L;
        SENSE_A;
        SENSE_FALLING_INT;
        break;
    }
}

  • 🌾在STC 无感BLDC代码中也有类似的启动代码:
/******************* 强制电机启动函数 ***************************/
void StartMotor(void)
{
	u16 timer,i;
	PIE = 0; NIE = 0;	// 关比较器中断,	PIE=1: 允许比较器上升沿中断, PIE=0: 禁止上升沿中断.	NIE=1: 允许比较器下降沿中断, NIE=0: 禁止下降沿中断.

	PWM_Value  = D_START_PWM;	// 初始占空比, 根据电机特性设置
	PWMA_CCR1H = (u8)(PWM_Value/256);
	PWMA_CCR1L = (u8)(PWM_Value%256);
	PWMA_CCR2H = (u8)(PWM_Value/256);
	PWMA_CCR2L = (u8)(PWM_Value%256);
	PWMA_CCR3H = (u8)(PWM_Value/256);
	PWMA_CCR3L = (u8)(PWM_Value%256);
	step = 0;	StepMotor();	Delay_n_ms(30);	// 初始位置
	step = 1;	StepMotor();	Delay_n_ms(20);	// 初始位置
	timer = 232;	//200电机启动

	while(1)
	{
		for(i=0; i<timer; i++)	delay_us(18);  //20根据电机加速特性, 最高转速等等调整启动加速速度
		timer -= timer /16;
		if(++step >= 6)	step = 0;
		StepMotor();
		if(timer < 40)	return;
	}
}


void StepMotor(void) // 换相序列函数
{
	switch(step)
	{
	case 0:  // AB  PWM1, PWM2_L=1
			PWMA_ENO = 0x00;	PWM1_L=0;	PWM3_L=0;
			Delay_500ns();
			PWMA_ENO = 0x01;		// 打开A相的高端PWM
			PWM2_L = 1;				// 打开B相的低端
			CMPEXCFG = 0;			// 比较器选择C相反电动势,  CMP+输入选择,0->P3.7(EMFC),1->P5.0(EMFA),2->P5.1(EMFB),3->ADCIN
			PIE = 0; NIE = 1;		// 比较器下降沿中断,	PIE=1: 允许比较器上升沿中断, PIE=0: 禁止上升沿中断.	NIE=1: 允许比较器下降沿中断, NIE=0: 禁止下降沿中断.
			break;
	case 1:  // AC  PWM1, PWM3_L=1
			PWMA_ENO = 0x01;	PWM1_L=0;	PWM2_L=0;	// 打开A相的高端PWM
			Delay_500ns();
			PWM3_L = 1;				// 打开C相的低端
			CMPEXCFG = 2;			// 比较器选择B相反电动势,  CMP+输入选择,0->P3.7(EMFC),1->P5.0(EMFA),2->P5.1(EMFB),3->ADCIN
			PIE = 1; NIE = 0;		// 比较器上升沿中断,	PIE=1: 允许比较器上升沿中断, PIE=0: 禁止上升沿中断.	NIE=1: 允许比较器下降沿中断, NIE=0: 禁止下降沿中断.
			break;
	case 2:  // BC  PWM2, PWM3_L=1
			PWMA_ENO = 0x00;	PWM1_L=0;	PWM2_L=0;
			Delay_500ns();
			PWMA_ENO = 0x04;		// 打开B相的高端PWM
			PWM3_L = 1;				// 打开C相的低端
			CMPEXCFG = 1;			// 比较器选择A相反电动势,  CMP+输入选择,0->P3.7(EMFC),1->P5.0(EMFA),2->P5.1(EMFB),3->ADCIN
			PIE = 0; NIE = 1;		// 比较器下降沿中断,	PIE=1: 允许比较器上升沿中断, PIE=0: 禁止上升沿中断.	NIE=1: 允许比较器下降沿中断, NIE=0: 禁止下降沿中断.
			break;
	case 3:  // BA  PWM2, PWM1_L=1
			PWMA_ENO = 0x04;	PWM2_L=0;	PWM3_L=0;	// 打开B相的高端PWM
			Delay_500ns();
			PWM1_L = 1;				// 打开C相的低端
			CMPEXCFG = 0;			// 比较器选择C相反电动势,  CMP+输入选择,0->P3.7(EMFC),1->P5.0(EMFA),2->P5.1(EMFB),3->ADCIN
			PIE = 1; NIE = 0;		// 比较器上升沿中断,	PIE=1: 允许比较器上升沿中断, PIE=0: 禁止上升沿中断.	NIE=1: 允许比较器下降沿中断, NIE=0: 禁止下降沿中断.
			break;
	case 4:  // CA  PWM3, PWM1_L=1
			PWMA_ENO = 0x00;	PWM2_L=0;	PWM3_L=0;
			Delay_500ns();
			PWMA_ENO = 0x10;		// 打开C相的高端PWM
			PWM1_L = 1;				// 打开A相的低端
			CMPEXCFG = 2;			// 比较器选择B相反电动势,  CMP+输入选择,0->P3.7(EMFC),1->P5.0(EMFA),2->P5.1(EMFB),3->ADCIN
			PIE = 0; NIE = 1;		// 比较器下降沿中断,	PIE=1: 允许比较器上升沿中断, PIE=0: 禁止上升沿中断.	NIE=1: 允许比较器下降沿中断, NIE=0: 禁止下降沿中断.
			break;
	case 5:  // CB  PWM3, PWM2_L=1
			PWMA_ENO = 0x10;	PWM1_L=0;	PWM3_L=0;	// 打开C相的高端PWM
			Delay_500ns();
			PWM2_L = 1;				// 打开B相的低端
			CMPEXCFG = 1;			// 比较器选择A相反电动势,  CMP+输入选择,0->P3.7(EMFC),1->P5.0(EMFA),2->P5.1(EMFB),3->ADCIN
			PIE = 1; NIE = 0;		// 比较器上升沿中断,	PIE=1: 允许比较器上升沿中断, PIE=0: 禁止上升沿中断.	NIE=1: 允许比较器下降沿中断, NIE=0: 禁止下降沿中断.
			break;

	default:
			break;
	}

	if(B_start)	// 启动时禁止下降沿和上升沿中断
	{
		CMPIF = 0;		//清除比较器中断标志
		PIE = 0; NIE = 0;		// 比较器上升沿中断,	PIE=1: 允许比较器上升沿中断, PIE=0: 禁止上升沿中断.	NIE=1: 允许比较器下降沿中断, NIE=0: 禁止下降沿中断.
	}
}

📓比较器中断代码

✨用于确定下一刻,应该换哪一相;以及设定下一次比较器触发电平模式。

//############################################################################
//
SIGNAL(TIMER2_COMPB_vect)	//SIG_OVERFLOW2 定时器2溢出
//############################################################################
{
}

//############################################################################
//SIG_COMPARATOR模拟比较器
// + Wird durch den Analogkomperator ausgelöst
// + Dadurch wird das Kommutieren erzeugt
SIGNAL(ANALOG_COMP_vect)
//############################################################################
{
    unsigned char sense = 0;
    do
    {
        if (SENSE_H) sense = 1;
        else sense = 0;
        switch (Phase)
        {
        case 0:
            STEUER_A_H;
            if (sense)
            {
                STEUER_C_L;
                if (ZeitZumAdWandeln) AdConvert();
                SENSE_FALLING_INT;
                SENSE_B;
                Phase++;
                CntKommutierungen++;
            }
            else
            {
                STEUER_B_L;
            }
            break;
        case 1:
            STEUER_C_L;
            if (!sense)
            {
                STEUER_B_H;
                if (ZeitZumAdWandeln) AdConvert();
                SENSE_A;
                SENSE_RISING_INT;
                Phase++;
                CntKommutierungen++;
            }
            else
            {
                STEUER_A_H;
            }

            break;
        case 2:
            STEUER_B_H;
            if (sense)
            {
                STEUER_A_L;
                if (ZeitZumAdWandeln) AdConvert();
                SENSE_C;
                SENSE_FALLING_INT;
                Phase++;
                CntKommutierungen++;
            }
            else
            {
                STEUER_C_L;
            }

            break;
        case 3:
            STEUER_A_L;
            if (!sense)
            {
                STEUER_C_H;
                if (ZeitZumAdWandeln) AdConvert();
                SENSE_B;
                SENSE_RISING_INT;
                Phase++;
                CntKommutierungen++;
            }
            else
            {
                STEUER_B_H;
            }


            break;
        case 4:
            STEUER_C_H;
            if (sense)
            {
                STEUER_B_L;
                if (ZeitZumAdWandeln) AdConvert();
                SENSE_A;
                SENSE_FALLING_INT;
                Phase++;
                CntKommutierungen++;
            }
            else
            {
                STEUER_A_L;
            }

            break;
        case 5:
            STEUER_B_L;
            if (!sense)
            {
                STEUER_A_H;
                if (ZeitZumAdWandeln) AdConvert();
                SENSE_C;
                SENSE_RISING_INT;
                Phase = 0;
                CntKommutierungen++;
            }
            else
            {
                STEUER_C_H;
            }
            break;
        }
    }
    while ((SENSE_L && sense) || (SENSE_H && !sense));
    ZeitZumAdWandeln = 0;
}

🔬移植初版工程源码

链接:https://pan.baidu.com/s/1kCNJCOLu4gqsP1KXwm9d3Q?pwd=6z15 
提取码:6z15

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

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

相关文章

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

文章目录 前言一、VGA概述1.1 简述1.2 管脚定义1.3 VGA显示原理1.4 VGA时序标准1.5 VGA 显示模式及相关参数 二、VGA显示自定义的汉字字符2.1 点阵汉字生成2.2 生成BMP文件2.3 生成txt文件2.4 实现效果 三、VGA显示条纹3.1 实现流程3.2 实现效果 四、VGA输出一幅彩色图像4.1 bm…

从旅游广告联想到《桃花源记》

近日收到《长江头条网》等知名网络自媒体相邀,促我写点儿旅游题材的文案。虽说笔者游历过许多名山大川的绝美风景区,但那是在70岁之前的事儿了。如今年逾78岁,纵使有少许自有资本能够支持出游,可体力难撑,岂不是花钱买罪受吗?而且,写没有亲身经历过的事挺难,即便发表出…

Plotly库利用滑块创建数据可视化

使用了Plotly库来创建一个数据可视化图表&#xff0c;并使用滑块来控制显示哪些数据 import plotly.graph_objects as go from plotly.subplots import make_subplots# 示例数据 x [1, 2, 3, 4, 5] y1 [1, 2, 3, 4, 5] y2 [5, 4, 3, 2, 1] y3 [2, 3, 1, 5, 4]# 创建子图 f…

基于jeecgboot-vue3的Flowable增加流程支持组件与element-plus组件导入支持

因为这个项目license问题无法开源&#xff0c;更多技术支持与服务请加入我的知识星球。 1、package.json文件需要增加相关流程组件&#xff0c;如下 "dependencies": {"element-plus/icons-vue": "^2.3.1","highlightjs/vue-plugin":…

JDBCTemplate介绍

Spring JDBC Spring框架对Spring的简单封装。提供一个JDBCTemplate对象简化JDBC开发 *步骤&#xff1a; 1、导入jar包 2、创建JDBCTemplate对象。依赖于数据源DataSource *JdbcTemplate templatenew JdbcTemplate(ds); 3、调用JdbcTemplate的方法来完成CRUD的操作 *update()&…

解决问题:Collecting package metadata (current_repodata.json)--faile

目录 解决步骤&#xff1a; 1、创建pip.ini文件&#xff1a;winR对话框中复制输入&#xff1a;%APPDATA%&#xff0c;然后回车。 2、conda添加清华源&#xff1a; 3、这些创建完&#xff0c;重启电脑就可以创建你的虚拟环境了 4、利用镜像源下载库&#xff1a; 5、查看to…

青鸟云报修系统:实现高效、便捷的维修申请处理

在日常生活和工作中&#xff0c;故障报修难免会遇到&#xff0c;售后报修服务则成为了解决问题的关键。纸质化售后报修维修申请单&#xff0c;作为报修流程中的重要一环&#xff0c;在一定程度上能够记录和追踪售后报修维修流程&#xff0c;但在实际操作过程中却存在着诸多弊端…

C# NetworkStream 流的详解与示例

文章目录 一、NetworkStream类的基本概念1.1 NetworkStream类概述1.2 NetworkStream类属性1.3 NetworkStream类方法 二、NetworkStream的连接方式三、NetworkStream的传输模式四、NetworkStream类示例服务器端代码&#xff1a;客户端代码&#xff1a; 五、总结 在C#中&#xff…

代码审计--一道简单的文件包含题目的多种利用方式

NO.1 传统方法 首先来看下代码 <?php error_reporting(0); if(isset($_GET["file"])){include($_GET["file"]); }else{highlight_file(__FILE__);phpinfo(); } ?>看完代码后再来学习学习函数吧&#xff0c;毕竟菜啊&#xff01;&#xff01;&…

webpack编译过程

webpack编译过程 初始化 此阶段&#xff0c;webpack会将**CLI参数**、**配置文件**、**默认配置**进行融合&#xff0c;形成一个最终的配置对象。​ 对配置的处理过程是依托一个第三方库yargs完成的 ​ 此阶段相对比较简单&#xff0c;主要是为接下来的编译阶段做必要的准备 ​…

那智不二越机器人维修案例分享

那智不二越工业机器人在工业范围内广泛应用于各种生产领域。其示教器作为人机交互的重要设备&#xff0c;常常需要定期维护和Nachi不二越机械手示教盒修理。 【Nachi不二越机器人示教器维修步骤】 1. 关闭电源 在进行任何那智不二越机器人维修操作之前&#xff0c;务必确保机器…

arc-eager算法XJTU-NLP自然语言处理技术期末考知识点

arc-eager算法&#xff1a;以我/做了/一个/梦为例来描述arc-eager算法的四个操作&#xff1a;shift&#xff0c;left-arc&#xff0c;right-arc&#xff0c;reduce XJTU-NLP期末考点2024版 题型&#xff1a;5*6简答题4*15计算题 简答题考点&#xff1a; &#xff08;1&#…

总结 HTTPS 的加密流程

一、前言 http是为了解决http存在的问题而在http基础上加入了SSL/TSL&#xff0c;在HTTP/2中TCP三次握手后会进入SSL/TSL握手&#xff0c;当SSL/TSL建立链接后&#xff0c;才会进行报文的传输。 二、HTTPS的混合加密 我们先来认识密钥&#xff1a; 密钥是用于加密和解密数据…

【spring】@PathVariable注解学习

PathVariable介绍 PathVariable是Spring框架中的一个注解&#xff0c;主要用于处理RESTful风格URL中的路径变量。在RESTful接口设计中&#xff0c;我们经常将资源的ID或者其他标识信息直接放在URL路径中&#xff0c;而不是作为查询参数。PathVariable注解使得控制器方法能够轻…

开源博客项目Blog .NET Core源码学习(22:App.Hosting项目结构分析-10)

本文学习并分析App.Hosting项目中后台管理页面的通知公告维护页面、友情链接维护页面。 通知公告维护页面 通知公告维护页面用于显示、检索、新建、编辑、删除通知公告数据&#xff0c;以便在前台页面的首页循环显示通知公告。通知公告维护页面附带一新建及编辑页面&#xff0…

hsql学习笔记

1. row_number() over (partition by uid order by dt 分析&#xff1a; row_number()&#xff1a; 这是一个窗口函数&#xff0c;用于为结果集中的每一行分配一个唯一的序号。默认情况下&#xff0c;这个序号是按照查询结果的顺序来分配的&#xff0c;但你可以通过OVER()子句…

docker搭建私有仓库并推送本地镜像

1、私仓搭建 docker pull registry#拉取镜像 docker images#查看镜像 mkdir -p /czx/myregistry 创建挂载目录 运行私有库registry (相当于本地有个是有docker hub) docker run -d -p 5000:5000 -v /czx/myregistry/:/tmp/registry --restartalways --privilegedtrue regist…

如何利用GitHubAction来发布自己的Python软件包

我们开发的python软件包如果想发布到网上&#xff0c;可以让其他人通过pip install下载&#xff0c;一般是把软件包发布到PYPI平台。 PYPI准备 我们要现在pypi注册登录一下 文件组织架构 一般的python软件包的文件组织架构为包名文件夹__init__.py程序&#xff0c;包文件夹的…

让写书人勇敢穿越纸海的迷雾

坚守纸海&#xff1a;让写书人勇敢穿越纸海的迷雾 你作为一位写书人&#xff0c;在创作过程中你需要坚守初心是非常重要的。在创作的过程中&#xff0c;你会遇到各种挑战和困难&#xff0c;你要勇敢面对迷雾中的挑战&#xff0c;并通过不懈的努力和决心&#xff0c;成功地穿越…

从反向传播(BP)到BPTT:详细数学推导【原理理解】

从反向传播到BPTT&#xff1a;详细推导与问题解析 在本文中&#xff0c;我们将从反向传播算法开始&#xff0c;详细推导出反向传播通过时间&#xff08;Backpropagation Through Time, BPTT&#xff09;算法。重点讨论BPTT中的梯度消失和梯度爆炸问题&#xff0c;并解释如何解…