linux内核timer_interrupt()源码

时间: 2023-06-17 17:05:01 浏览: 57
以下是Linux内核4.19版本中timer_interrupt()函数的源码实现: ``` asmlinkage __visible void __weak timer_interrupt(struct pt_regs *regs) { struct cpu_data *cpu = get_cpu_ptr(smp_processor_id()); struct clock_event_device *evt = cpu->evtdev; unsigned long next_jiffies = jiffies + 1; if (unlikely(time_after_eq(next_jiffies, cpu->last_jiffies + TICK_NSEC))) { /* * Some of this is really subtle. If we're in the middle of a tick * already, we don't want to update the tick count - that could * confuse the heck out of anyone trying to do timing. So make sure * we don't update the tick until after the tick period has * expired. */ if (time_after(next_jiffies, cpu->last_jiffies + TICK_NSEC)) { int clock_was_set = 0; while (time_after_eq(next_jiffies, cpu->last_jiffies + TICK_NSEC)) { cpu->last_jiffies += TICK_NSEC; update_wall_time(); clock_was_set = tick_nohz_update_jiffies(&cpu->tick_dep_mask); if (cpu_is_offline(smp_processor_id())) return; } if (clock_was_set) tick_program_event(evt, cpu->next_timer_interrupt); } /* * We must make sure that the jiffies update is visible * before we test time_after_eq(). */ smp_wmb(); if (time_after_eq(next_jiffies, READ_ONCE(jiffies))) __generic_touch_nmi_watchdog(); if (unlikely(in_nmi())) return; /* * If we missed any timer interrupts, correct this now * by advancing the local timer and updating wall time * again. */ while (time_after_eq(next_jiffies, READ_ONCE(jiffies))) { cpu->last_jiffies += TICK_NSEC; update_wall_time(); tick_nohz_idle_enter(); } } evt->event_handler(evt); } ``` timer_interrupt()函数是中断处理程序,用于处理定时器中断。该函数首先获取当前CPU的事件设备指针,然后计算出下一次中断的时间,如果下一次中断的时间已经到了,则更新 jiffies 值并调用事件处理函数。如果下一次中断的时间还没有到,则继续等待下一次中断。函数中还包含了一些调用其他函数的代码块,用于更新时间值、设置时钟事件等。

相关推荐

timer_interrupt() 是 Linux 内核中的一个定时器中断处理函数,它主要用于处理内核中的各种定时器事件,包括时钟中断、定时器任务等。 源码如下: c void __irqentry timer_interrupt(struct pt_regs *regs) { ... update_process_times(user_mode(regs)); profile_tick(CPU_PROFILING, user_mode(regs), regs); if (user_mode(regs)) return; irq_enter(); #ifdef CONFIG_NO_HZ_COMMON /* * The tick broadcast device is disabled after the first * CPU goes offlined, see tick_nohz_enable. */ if (tick_nohz_tick_stopped()) goto out; #endif tick_check_idle(TICK_NMI_SAFE); /* * Tickless idle is in progress. */ if (idle_cpu(smp_processor_id())) { watchdog_touch(); smp_idle_check(); goto out; } /* * Check if we need to do anything at all: */ if (!tick_check_oneshot_broadcast(tick_nohz_full_cpu_idle())) { if (tick_check_oneshot() && !tick_check_broadcast_expired() && !tick_broadcast_oneshot_active()) { tick_program_event(tick_oneshot_broadcast, oneshot_timer.expires); goto out; } if (tick_check_broadcast_spurious()) goto out; if (tick_check_cpu_dead(cpu) || tick_check_new_device(cpu)) goto out; tick_check_replacement(cpu); } /* * Re-enable periodic tick if it is stopped and there are no * oneshot or broadcast events pending: */ if (tick_check_periodic() && !tick_check_oneshot_active() && !tick_check_broadcast_active()) tick_program_event(tick_periodic, tick_next_period); out: irq_exit(); ... } 该函数的主要流程如下: 1. 调用 update_process_times() 和 profile_tick() 更新进程的时间信息和性能分析信息。 2. 判断是否是用户态,如果是则直接返回。 3. 调用 irq_enter() 进入中断上下文。 4. 检查 tickless idle 是否正在进行,如果是,则直接返回。 5. 检查是否正在进行 idle,如果是,则调用 watchdog_touch() 和 smp_idle_check(),并直接返回。 6. 检查是否需要进行任何操作。 7. 如果需要,检查是否需要启动一次性定时器事件。 8. 如果需要,检查是否需要启动广播定时器事件。 9. 如果需要,检查是否需要停止定时器,并重新启动。 10. 调用 irq_exit() 退出中断上下文。 总的来说,timer_interrupt() 函数主要用于检查和处理各种定时器事件,以保证内核的正常运行。这些事件包括一次性定时器、广播定时器、周期性定时器等。

int itcs_timer_irq(int idx, void *arg) { timer_priv_t *timer_priv = (timer_priv_t *)arg; uint32_t tempregisr = 0; switch (timer_priv->timeridx) { case 1: tempregisr = readl(timer_priv->base + TIMER_ISR_C1); // printf("BEFORE READ COUNT1 ISR STAT RET :%08x\n",tempregisr); if (GET_BIT(tempregisr, 4) == 1) { // printf("OVERFLOW INTERRUPT OCCUR\n"); timer_priv->enum_interrupt = TIMER_OVERFLOW_INTERRUPT; } if (GET_BIT(tempregisr, 0) == 1) { g_endtime = get_timer(0); // printf("INTERVAL INTERRUPT OCCUR\n"); timer_priv->enum_interrupt = TIMER_INTERVAL_INTERRUPT; } if (GET_BIT(tempregisr, 1) == 1) { g_endtimematch1 = get_timer(0); // printf("MATCH1 INTERRUPT OCCUR\n"); timer_priv->enum_interrupt = TIMER_MATCH1_INTERRUPT; } if (GET_BIT(tempregisr, 2) == 1) { g_endtimematch2 = get_timer(0); // printf("MATCH2 INTERRUPT OCCUR\n"); timer_priv->enum_interrupt = TIMER_MATCH2_INTERRUPT; } if (GET_BIT(tempregisr, 3) == 1) { g_endtimematch3 = get_timer(0); // printf("MATCH3 INTERRUPT OCCUR\n"); timer_priv->enum_interrupt = TIMER_MATCH3_INTERRUPT; } tempregisr = readl(timer_priv->base + TIMER_ISR_C1); // printf("AFTER READ COUNT1 ISR STAT RET :%08x\n",tempregisr); break; case 2: tempregisr = readl(timer_priv->base + TIMER_ISR_C2); // printf("BEFORE READ COUNT2 ISR STAT RET :%08x\n",tempregisr); if (GET_BIT(tempregisr, 4) == 1) { // printf("OVERFLOW INTERRUPT OCCUR\n"); timer_priv->enum_interrupt = TIMER_OVERFLOW_INTERRUPT; } if (GET_BIT(tempregisr, 0) == 1) { g_endtime = get_timer(0); // printf("INTERVAL INTERRUPT OCCUR\n"); timer_priv->enum_interrupt = TIMER_INTERVAL_INTERRUPT; } if (GET_BIT(tempregisr, 1) == 1) { // printf("MATCH1 INTERRUPT OCCUR\n"); g_endtimematch1 = get_timer(0); timer_priv->enum_interrupt = TIMER_MATCH1_INTERRUPT; } if (GET_BIT(tempregisr, 2) == 1) { g_endtimematch2 = get_timer(0); // printf("MATCH2 INTERRUPT OCCUR\n"); timer_priv->enum_interrupt = TIMER_MATCH2_INTERRUPT; } if (GET_BIT(tempregisr, 3) == 1) { g_endtimematch3 = get_timer(0); // printf("MATCH3 INTERRUPT OCCUR\n"); timer_priv->enum_interrupt = TIMER_MATCH3_INTERRUPT; } tempregisr = readl(timer_priv->base + TIMER_ISR_C2); // printf("AFTER READ COUNT2 ISR STAT RET :%08x\n",tempregisr); break; case 3: tempregisr = readl(timer_priv->base + TIMER_ISR_C3); // printf("BEFORE READ COUNT3 ISR STAT RET :%08x\n",tempregisr); if (GET_BIT(tempregisr, 4) == 1) { // printf("OVERFLOW INTERRUPT OCCUR\n"); timer_priv->enum_interrupt = TIMER_OVERFLOW_INTERRUPT; } if (GET_BIT(tempregisr, 0) == 1) { g_endtime = get_timer(0); // printf("INTERVAL INTERRUPT OCCUR\n"); timer_priv->enum_interrupt = TIMER_INTERVAL_INTERRUPT; } if (GET_BIT(tempregisr, 1) == 1) { g_endtimematch1 = get_timer(0); // printf("MATCH1 INTERRUPT OCCUR\n"); timer_priv->enum_interrupt = TIMER_MATCH1_INTERRUPT; } if (GET_BIT(tempregisr, 2) == 1) { g_endtimematch2 = get_timer(0); // printf("MATCH2 INTERRUPT OCCUR\n"); timer_priv->enum_interrupt = TIMER_MATCH2_INTERRUPT; } if (GET_BIT(tempregisr, 3) == 1) { g_endtimematch3 = get_timer(0); // printf("MATCH3 INTERRUPT OCCUR\n"); timer_priv->enum_interrupt = TIMER_MATCH3_INTERRUPT; } tempregisr = readl(timer_priv->base + TIMER_ISR_C3); // printf("AFTER READED COUNT3 ISR STAT RET :%08x\n",readregisr); break; default: break; } if (timer_priv->cb_event) { timer_priv->cb_event(timer_priv); } return 0; }

Linux 定时器 timer_list 是一个内核数据结构,用于管理内核中的定时器。它是一个双向链表,每个节点表示一个定时器。timer_list 的定义位于 头文件中。 每个 timer_list 节点的定义如下: c struct timer_list { struct list_head entry; // 定时器节点的链表指针 unsigned long expires; // 定时器的到期时间 void (*function)(unsigned long); // 定时器回调函数 unsigned long data; // 传递给回调函数的参数 struct tvec_base *base; // 定时器所属的时间轮 int slack; // 定时器的松弛时间 }; 其中,entry 是一个 list_head 结构,用于将节点连接到定时器链表中。expires 表示定时器的到期时间,以 jiffies 单位表示。function 是定时器的回调函数,在定时器到期时被调用。data 是传递给回调函数的参数。base 表示定时器所属的时间轮,slack 是定时器的松弛时间,用于处理定时器的精度。 在使用 timer_list 时,可以使用以下函数进行初始化和操作: - timer_setup(struct timer_list *timer, void (*function)(unsigned long), unsigned int flags):初始化一个定时器,并指定回调函数和标志。 - init_timer(struct timer_list *timer):初始化一个定时器。 - add_timer(struct timer_list *timer):将定时器添加到定时器链表中。 - del_timer(struct timer_list *timer):从定时器链表中删除定时器。 - mod_timer(struct timer_list *timer, unsigned long expires):修改定时器的到期时间。 这些函数可以通过 头文件中的宏来调用。通过操作 timer_list,可以实现在 Linux 内核中的定时器功能。
对于 MSP432 微控制器中的定时器中断,通常情况下,你不应该在中断服务程序(ISR)中直接调用 Timer_A_getInterruptStatus() 函数来检查中断状态。这是因为在 ISR 中,需要尽量保持执行时间短,以避免延迟其他重要的系统任务。 相反,你可以在 ISR 中设置一个标志位(例如一个全局变量),表示定时器中断已经发生。然后,在主循环或其他非中断上下文中,检查这个标志位并执行相应的处理逻辑。 以下是一个示例代码片段,展示了如何在中断服务程序和主循环中处理定时器中断: c #include <ti/devices/msp432p4xx/driverlib/driverlib.h> volatile uint8_t timerInterruptFlag = 0; // 定时器中断服务程序 void TIMER0_A0_IRQHandler(void) { // 处理定时器中断 // 设置标志位 timerInterruptFlag = 1; // 清除中断标志位 Timer_A_clearInterruptFlag(TIMER_A0_BASE); } int main(void) { // 其他初始化代码... // 配置定时器中断 Interrupt_enableInterrupt(INT_TA0_0); // 启用全局中断 Interrupt_enableMaster(); while (1) { // 检查定时器中断标志位 if (timerInterruptFlag) { // 进入了定时器中断 // 处理你的逻辑... // 清除标志位 timerInterruptFlag = 0; } // 主循环代码... } } 在上述示例代码中,我们使用了一个名为 timerInterruptFlag 的全局变量作为中断标志位。在定时器中断服务程序中,我们设置了这个标志位,并在主循环中检查和清除它。 请注意,如果你需要在中断服务程序中执行更复杂的操作,例如处理大量数据或进行长时间的计算,那么你可能需要使用更高级的技术,如使用循环缓冲区或任务调度器来处理这些任务,以避免影响其他重要的系统操作。
根据提供的代码,你正在使用 Timer A0 模块生成两个 PWM 波形,并且在函数 pwmInit 中进行了相应的初始化配置。下面是对你的代码进行解释和补充说明: 1. PWM 配置结构体:你定义了两个 Timer_A_PWMConfig 类型的结构体变量 pwmConfigL 和 pwmConfigR,分别用于配置左右两个 PWM 波形的参数。 2. 时钟配置:在函数 pwmInit 中,你使用了 REFO 作为参考振荡器,并设置 SMCLK 的时钟源为 REFO。同时,通过设置 CS_CLOCK_DIVIDER_2,将 SMCLK 的频率分频为 REFO 频率的一半。 3. 引脚配置:使用 GPIO_setAsPeripheralModuleFunctionOutputPin 函数将 P2.4 和 P2.5 引脚配置为 PWM 输出引脚。 4. 生成 PWM 波形:通过调用 Timer_A_generatePWM 函数来生成 PWM 波形。对于左侧 PWM 波形,传递了 TIMER_A_CAPTURECOMPARE_REGISTER_1 作为比较寄存器参数;对于右侧 PWM 波形,传递了 TIMER_A_CAPTURECOMPARE_REGISTER_2 作为比较寄存器参数。 5. 中断和睡眠模式:通过调用 Interrupt_enableSleepOnIsrExit 和 Interrupt_enableMaster 函数来使能中断和睡眠模式。 请注意,上述代码片段中的具体配置参数(如时钟分频器、引脚定义、PWM 周期等)需要根据你的实际需求进行调整。此外,还需要确保所选的引脚与 Timer A0 模块的 PWM 输出引脚相匹配,以及正确设置系统时钟和时钟源。 最后,建议参考 MSP432 的技术文档、相关开发工具的使用说明以及芯片厂商提供的示例代码来获取准确的配置细节和函数调用。
Linux中的TIMER_REAL定时器是一种基于实时时钟的定时器。它使用了系统的真实时间来进行定时操作。当定时器到期时,会生成一个SIGALRM信号,可以用来触发特定的操作或处理程序。 你可以使用timer_create()函数来创建一个TIMER_REAL定时器。例如: c #include <stdio.h> #include <signal.h> #include <unistd.h> #include <time.h> timer_t timerid; void timer_handler(int sig) { printf("Timer expired!\n"); } int main() { struct sigevent sevp; struct itimerspec its; // 设置定时器处理程序 signal(SIGALRM, timer_handler); // 创建定时器 sevp.sigev_notify = SIGEV_SIGNAL; sevp.sigev_signo = SIGALRM; timer_create(CLOCK_REALTIME, &sevp, &timerid); // 设置定时器参数 its.it_value.tv_sec = 5; // 第一次触发的时间(秒) its.it_value.tv_nsec = 0; // 第一次触发的时间(纳秒) its.it_interval.tv_sec = 1; // 重复触发的时间间隔(秒) its.it_interval.tv_nsec = 0; // 重复触发的时间间隔(纳秒) // 启动定时器 timer_settime(timerid, 0, &its, NULL); //等待定时器触发 sleep(10); // 删除定时器 timer_delete(timerid); return 0; } 以上的代码演示了创建一个TIMER_REAL定时器并设置参数,然后等待定时器到期。当定时器到期时,会调用timer_handler函数打印一条信息。这个例子中,定时器将在5秒后第一次触发,然后每1秒重复触发一次。 希望能对你有所帮助!如果你有更多问题,请继续提问。
在Linux平台上使用timer_create函数可以创建一个定时器。在Delphi中,可以通过调用Linux系统库头文件来实现该函数的调用。下面是一个简单的示例代码: delphi unit LinuxTimer; interface uses LinuxApi; type TTimer = class private FTimerID: timer_t; FInterval: Cardinal; FOnTimer: TNotifyEvent; FIsStarted: Boolean; FTimerSpec: itimerspec; procedure SetInterval(const Value: Cardinal); public constructor Create; destructor Destroy; override; procedure Start; procedure Stop; property Interval: Cardinal read FInterval write SetInterval; property OnTimer: TNotifyEvent read FOnTimer write FOnTimer; property IsStarted: Boolean read FIsStarted; end; implementation uses SysUtils; { TTimer } constructor TTimer.Create; begin inherited; FTimerID := 0; FInterval := 1000; FIsStarted := False; end; destructor TTimer.Destroy; begin Stop; inherited; end; procedure TTimer.SetInterval(const Value: Cardinal); begin if FInterval <> Value then begin FInterval := Value; if IsStarted then begin Stop; Start; end; end; end; procedure TTimer.Start; begin if not IsStarted then begin FillChar(FTimerSpec, SizeOf(FTimerSpec), 0); FTimerSpec.it_interval.tv_sec := FInterval div 1000; FTimerSpec.it_interval.tv_nsec := (FInterval mod 1000) * 1000000; FTimerSpec.it_value.tv_sec := FInterval div 1000; FTimerSpec.it_value.tv_nsec := (FInterval mod 1000) * 1000000; if timer_create(CLOCK_REALTIME, nil, @FTimerID) = 0 then begin if timer_settime(FTimerID, 0, @FTimerSpec, nil) = 0 then FIsStarted := True else timer_delete(FTimerID); end; end; end; procedure TTimer.Stop; begin if IsStarted then begin FTimerSpec.it_interval.tv_sec := 0; FTimerSpec.it_interval.tv_nsec := 0; FTimerSpec.it_value.tv_sec := 0; FTimerSpec.it_value.tv_nsec := 0; timer_settime(FTimerID, 0, @FTimerSpec, nil); timer_delete(FTimerID); FIsStarted := False; end; end; end. 这是一个简单的封装,使用时只需要创建一个TTimer对象,并调用Start方法就可以启动一个定时器。在该代码中,使用了Linux API中的timer_create和timer_settime函数来实现定时器功能。同时,该封装使用了Delphi中的事件模型,通过设置OnTimer事件,在定时器到期时,会触发该事件,从而完成定时器任务。

使用 CCS(Code Composer Studio)和 msp430f5529 基于 driverlib.h 库编写代码,请具体说明如下代码的效果 #include "driverlib.h" #define COMPARE_VALUE 20000 void main (void) { //Stop WDT WDT_A_hold(WDT_A_BASE); //Set P1.0 to output direction GPIO_setAsOutputPin( GPIO_PORT_P1, GPIO_PIN0 ); //Start timer in continuous mode sourced by SMCLK Timer_A_initContinuousModeParam initContParam = {0}; initContParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK; initContParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_10; initContParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE; initContParam.timerClear = TIMER_A_DO_CLEAR; initContParam.startTimer = false; Timer_A_initContinuousMode(TIMER_A1_BASE, &initContParam); //Initiaze compare mode Timer_A_clearCaptureCompareInterrupt(TIMER_A1_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_0 ); Timer_A_initCompareModeParam initCompParam = {0}; initCompParam.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_0; initCompParam.compareInterruptEnable = TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE; initCompParam.compareOutputMode = TIMER_A_OUTPUTMODE_OUTBITVALUE; initCompParam.compareValue = COMPARE_VALUE; Timer_A_initCompareMode(TIMER_A1_BASE, &initCompParam); Timer_A_startCounter( TIMER_A1_BASE, TIMER_A_CONTINUOUS_MODE ); //Enter LPM0, enable interrupts __bis_SR_register(LPM0_bits + GIE); //For debugger __no_operation(); } //****************************************************************************** // //This is the TIMER1_A3 interrupt vector service routine. // //****************************************************************************** #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=TIMER1_A0_VECTOR __interrupt #elif defined(__GNUC__) __attribute__((interrupt(TIMER1_A0_VECTOR))) #endif void TIMER1_A0_ISR (void) { uint16_t compVal = Timer_A_getCaptureCompareCount(TIMER_A1_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_0) + COMPARE_VALUE; //Toggle P1.0 GPIO_toggleOutputOnPin( GPIO_PORT_P1, GPIO_PIN0 ); //Add Offset to CCR0 Timer_A_setCompareValue(TIMER_A1_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_0, compVal ); }

这段代码的效果是使用 MSP430F5529 的 Timer A 模块和 GPIO 控制 P1.0 引脚,通过定时器中断实现周期性地改变 P1.0 引脚的状态。 具体的代码功能如下: 1. 停止看门狗定时器(WDT_A):使用 WDT_A_hold() 函数停止看门狗定时器的计数。 2. 设置 P1.0 引脚为输出方向:使用 GPIO_setAsOutputPin() 函数将 P1.0 引脚设置为输出模式,即将其配置为输出引脚。 3. 初始化 Timer A 模块:通过 Timer_A_initContinuousMode() 函数初始化 Timer A 模块为连续模式,使用 SMCLK 作为时钟源,并设置时钟分频器为 10。 4. 初始化比较模式:使用 Timer_A_initCompareMode() 函数初始化 Timer A 的比较模式,在比较寄存器 0 中设置比较值为 COMPARE_VALUE,使得当计数器计数达到该值时触发中断。 5. 启动计数器:通过 Timer_A_startCounter() 函数启动 Timer A 的计数器。 6. 进入低功耗模式 LPM0 并启用中断:使用 __bis_SR_register() 函数将处理器置于低功耗模式 LPM0,并使能全局中断(GIE)。 7. 定时器中断服务函数:在 TIMER1_A0_VECTOR 中断向量中,定义了 TIMER1_A0_ISR() 中断服务函数。该函数在每次 Timer A 达到比较值 COMPARE_VALUE 时被调用。 a. 获取当前比较寄存器的值,并加上 COMPARE_VALUE,得到新的比较值 compVal。 b. 使用 GPIO_toggleOutputOnPin() 函数切换 P1.0 引脚的输出状态,实现周期性地改变 P1.0 的状态。 c. 使用 Timer_A_setCompareValue() 函数将比较寄存器 0 的值设置为 compVal,以更新下一次中断的比较值。 8. 空操作(NOP):使用 __no_operation() 指令作为调试用途,可忽略。 总结起来,这段代码通过定时器中断实现了周期性地改变 P1.0 引脚的状态,从而产生周期性的信号或闪烁效果。
这段代码是使用定时器2的通道1来生成PWM信号的配置代码。下面是对每个配置项的解释: - timer_ocintpara.outputstate = TIMER_CCX_ENABLE;:主输出通道开启。 - timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;:互补输出通道关闭。 - timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;:主输出极性高电平有效。 - timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;:互补输出极性高电平有效。 - timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;:主输出空闲状态为低电平。 - timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;:互补输出空闲状态为低电平。 - timer_channel_output_config(TIMER2, TIMER_CH_1, &timer_ocintpara);:配置定时器2的通道1的输出参数。 接下来是对PWM信号的具体配置: - timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_1, 500);:设置PWM脉冲宽度为500。 - timer_channel_output_mode_config(TIMER2, TIMER_CH_1, TIMER_OC_MODE_PWM0);:设置PWM0模式,即高电平持续时间从计数器开始到达比较值时,输出为高电平,否则为低电平。 - timer_channel_output_shadow_config(TIMER2, TIMER_CH_1, TIMER_OC_SHADOW_DISABLE);:关闭输出通道的预装载功能。 通过以上配置,定时器2的通道1将以PWM0模式生成PWM信号,脉冲宽度为500。主输出通道开启,互补输出通道关闭,并且主输出极性和互补输出极性均为高电平有效。在空闲状态时,主输出通道和互补输出通道都为低电平。

最新推荐

基于MATLAB下的appdesigner简单的黑体辐射虚拟仿真实验源码+项目说明.zip

【资源说明】 1、该资源包括项目的全部源码,下载可以直接使用! 2、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,作为参考资料学习借鉴。 3、本资源作为“参考资料”如果需要实现其他功能,需要能看懂代码,并且热爱钻研,自行调试。 基于MATLAB下的appdesigner简单的黑体辐射虚拟仿真实验源码+项目说明.zip

day13-节后复习1.zip

day13-节后复习1.zip

输入输出方法及常用的接口电路资料PPT学习教案.pptx

输入输出方法及常用的接口电路资料PPT学习教案.pptx

管理建模和仿真的文件

管理Boualem Benatallah引用此版本:布阿利姆·贝纳塔拉。管理建模和仿真。约瑟夫-傅立叶大学-格勒诺布尔第一大学,1996年。法语。NNT:电话:00345357HAL ID:电话:00345357https://theses.hal.science/tel-003453572008年12月9日提交HAL是一个多学科的开放存取档案馆,用于存放和传播科学研究论文,无论它们是否被公开。论文可以来自法国或国外的教学和研究机构,也可以来自公共或私人研究中心。L’archive ouverte pluridisciplinaire

Office 365常规运维操作简介

# 1. Office 365概述 ## 1.1 Office 365简介 Office 365是由微软提供的云端应用服务,为用户提供办公软件和生产力工具的订阅服务。用户可以通过互联网在任何设备上使用Office应用程序,并享受文件存储、邮件服务、在线会议等功能。 ## 1.2 Office 365的优势 - **灵活性**:用户可以根据实际需求选择不同的订阅计划,灵活扩展或缩减服务。 - **便捷性**:无需安装繁琐的软件,随时随地通过互联网访问Office应用程序和文件。 - **协作性**:多人可同时编辑文档、实时共享文件,提高团队协作效率。 - **安全性**:微软提供安全可靠

如何查看linux上安装的mysql的账号和密码

你可以通过以下步骤查看 Linux 上安装的 MySQL 的账号和密码: 1. 进入 MySQL 安装目录,一般是 /usr/local/mysql/bin。 2. 使用以下命令登录 MySQL: ``` ./mysql -u root -p ``` 其中,-u 表示要使用的用户名,这里使用的是 root;-p 表示需要输入密码才能登录。 3. 输入密码并登录。 4. 进入 MySQL 的信息库(mysql): ``` use mysql; ``` 5. 查看 MySQL 中的用户表(user): ``` se

最新电力电容器及其配套设备行业安全生产设备设施及隐患排查治理.docx

2021年 各行业安全生产教育培训

"互动学习:行动中的多样性与论文攻读经历"

多样性她- 事实上SCI NCES你的时间表ECOLEDO C Tora SC和NCESPOUR l’Ingén学习互动,互动学习以行动为中心的强化学习学会互动,互动学习,以行动为中心的强化学习计算机科学博士论文于2021年9月28日在Villeneuve d'Asq公开支持马修·瑟林评审团主席法布里斯·勒菲弗尔阿维尼翁大学教授论文指导奥利维尔·皮耶昆谷歌研究教授:智囊团论文联合主任菲利普·普雷教授,大学。里尔/CRISTAL/因里亚报告员奥利维耶·西格德索邦大学报告员卢多维奇·德诺耶教授,Facebook /索邦大学审查员越南圣迈IMT Atlantic高级讲师邀请弗洛里安·斯特鲁布博士,Deepmind对于那些及时看到自己错误的人...3谢谢你首先,我要感谢我的两位博士生导师Olivier和Philippe。奥利维尔,"站在巨人的肩膀上"这句话对你来说完全有意义了。从科学上讲,你知道在这篇论文的(许多)错误中,你是我可以依

5G新空口技术:NR(New Radio)简介

# 1. 5G技术概述 ## 1.1 5G技术的发展历程 5G技术作为第五代移动通信技术,经历了从需求提出、标准制定到商用推广的漫长历程。早在2012年,各国就开始探讨5G技术的发展和应用,随后在2015年ITU正式确定5G技术的三项技术指标:高速率、低时延和大连接。在2019年,全球开始迎来了5G商用的浪潮,5G技术从理论研究逐步走向实际应用。 ## 1.2 5G技术的应用场景和优势 5G技术以其高速率、大容量和低时延的特点,为诸多行业带来了革命性的变革。在工业领域,通过5G技术的应用,可以实现工业自动化、智能制造等场景;在医疗领域,5G技术可以支持远程手术、远程诊断等应用;在智能交通领

python使用music21库解析midi格式文件后,将解析到的pitch音符整体升、降调怎么做?

在music21库中,可以使用transpose()方法来对音符进行升降调。具体来说,可以先解析MIDI文件,然后获取所有的音符对象,并将它们传入transpose()方法中,同时指定升降调的半音数。例如,将所有音符整体升一个半音可以使用以下代码: ```python from music21 import * # 解析MIDI文件 midi = converter.parse('example.mid') # 获取所有的音符对象 notes = midi.flat.notes # 将所有音符整体升一个半音 notes.transpose(1, inPlace=True) # 保存修