为什么叫猪流感? 为什么H1N1病毒以前叫猪流感病毒?

本文解释了H1N1病毒最初被称为“猪流感”的原因:实验室测试显示其许多基因与北美的猪流感病毒相似。但进一步研究表明,该病毒包含来自欧洲和亚洲猪流感病毒的基因以及人类基因,因此被科学家称为“四重组”病毒。

Why is this new H1N1 virus sometimes called “swine flu”?


 This virus was originally referred to as “swine flu” because laboratory testing showed that many of the genes in this new virus were very similar to influenza viruses that normally occur in pigs in North America. But further study has shown that this new virus is very different from what normally circulates in North American pigs. It has two genes from flu viruses that normally circulate in pigs in Europe and Asia and avian genes and human genes. Scientists call this a “quadruple reassortant” virus.

这种病毒最初是被称为“猪流感” ,因为实验室测试表明,这一新的病毒的许多基因与通常发生在北美的猪身上的非常类似的流感病毒,。

不过更多的研究显示,这个新的病毒与北美猪的病毒非常不一样。他有2个欧洲和亚洲禽流感的基因以及人类的基因。科学界称这个为“quadruple reassortant”病毒

<think>我们正在分析一段嵌入式C代码,该代码是一个定时器中断服务例程(TM1_Isr)。用户报告了两个问题: 1. H1跳变不稳定 2. num_不累加 代码: void TM1_Isr() interrupt 3 { num_=abs(gyro_z); if(junC1>=3000&&H2==0){H1=!H1;} if(H1==1){kp*=h; num_++;} if(num_>=300&&H1==1){H1=!H1; num_=0; H2=!H2; num1++;} if(junC1>=3000&&H2==1){kp/=h;} if(num1>=250){H2=!H2;} } 我们逐步分析: 1. 首先,每次中断发生时,将num_设置为abs(gyro_z)的绝对值。注意,这里覆盖了num_之前的值。 2. 然后,检查junC1>=3000且H2==0,如果满足,则翻转H1(取反)。 3. 如果H11,则执行kp乘以h,并且num_自增(注意:前面num_被赋值为abs(gyro_z),这里又自增,所以num_的值是abs(gyro_z)+1?但注意,这个自增是在赋值之后发生的,所以实际上num_的值是abs(gyro_z)+1) 4. 然后,如果num_>=300且H11,则翻转H1,将num_重置为0,翻转H2,并且num1自增。 5. 接着,如果junC1>=3000且H2为1,则kp除以h。 6. 最后,如果num1>=250,翻转H2。 问题1:H1跳变不稳定 可能的原因: a. 中断触发频率高,而条件junC1>=3000可能在一段时间内持续满足,导致H1被连续翻转多次。 例如,如果junC1>=3000的条件在多个中断周期内都为真,且H2为0,那么每个中断都会翻转H1,导致H1快速变化。 b. 另外,H1的翻转条件有两个:一个是junC1>=3000且H2==0(在代码第二行),另一个是num_>=300且H1==1(在代码第四行)。这两个条件可能互相干扰。 问题2:num_不累加 从代码中我们看到: num_ = abs(gyro_z); // 每次中断都重新赋值 if(H1==1){ num_++; } // 然后在H1==1时自增 所以,每次中断进入,num_都被重置为abs(gyro_z),然后只有当H1==1时才自增1。这样,num_的值主要取决于abs(gyro_z)的值,而不是持续累加。 用户期望的可能是num_能够持续累加,但实际上每次中断都会用新的gyro_z的绝对值覆盖,所以即使H1==1时自增,也仅仅是在当前abs(gyro_z)的基础上加1,然后下一次中断又会被新的abs(gyro_z)覆盖。 因此,num_不累加的原因在于每次中断都重新赋值,而自增操作只增加1,然后又被覆盖。 另外,注意在第四个条件中,当num_>=300且H1==1时,会将num_重置为0。但是,由于num_被重新赋值,可能很难达到300(除非gyro_z的值很大,或者中断次数足够多使得自增达到300?但实际上每次中断都被覆盖,所以自增的效果被覆盖了)。 如何修正? 对于num_不累加的问题,如果用户希望num_累计中断次数(在H1==1的条件下),那么应该去掉每次中断的重新赋值,而改为仅在需要重置时清零,其他时候累加。 例如: 将 num_ = abs(gyro_z); 去掉,改成在中断中只做自增(在H1==1时)和清零(在触发条件时)。 但注意,用户代码中num_还有其他用途吗?这里看到num_被用于条件判断(num_>=300),所以用户可能是想累计在H1==1状态下的中断次数。 因此,建议修改为: void TM1_Isr() interrupt 3 { // 移除 num_ = abs(gyro_z); // 不再每次重置 if(junC1>=3000&&H2==0){H1=!H1;} if(H1==1){ kp *= h; num_++; // 在H1==1时,每次中断自增1 } if(num_>=300 && H1==1){ H1 = !H1; num_ = 0; H2 = !H2; num1++; } if(junC1>=3000&&H2==1){kp/=h;} if(num1>=250){H2=!H2;} } 这样,num_就会在每次中断且H1==1时自增,直到达到300后被清零。 但是,注意原代码中还有一处使用了num_:条件junC1>=3000&&H2==0时翻转H1,这个翻转可能会与自增操作同时发生吗?需要分析逻辑。 另外,H1跳变不稳定的问题,可能由于junC1>=3000条件持续满足导致连续翻转。为了避免这种情况,可以考虑使用状态机或者标志位来确保条件只触发一次。 例如,可以设置一个标志,当翻转一次后,等待条件不满足再复位标志,防止连续翻转。 但是,由于用户代码中没有上下文,我们只能根据现有代码分析。 另外,注意在H1翻转的条件中,有一个条件是num_>=300且H1==1,这个条件会翻转H1并重置num_。而另一个条件是junC1>=3000且H2==0,这个条件也会翻转H1。 这两个条件可能在不同的时刻触发,导致H1被多次翻转。 如果用户希望H1的状态变化是稳定的,可能需要重新设计状态转换逻辑,避免多个条件同时能够改变同一个状态。 总结: 1. num_不累加的原因是每次中断都被abs(gyro_z)覆盖,修复方法是移除覆盖操作,改为只自增和清零。 2. H1跳变不稳定可能是因为条件junC1>=3000在多个中断周期内满足,导致连续翻转。解决方法是使用边沿触发或者状态标志,确保一次条件满足只翻转一次。 由于中断服务程序执行频率高,建议: - 对于junC1的判断,可以改为只在junC1从低于3000变为大于等于3000时翻转H1(上升沿触发),这样避免连续触发。 - 另外,注意变量junC1、gyro_z等可能是在主程序或其他中断中修改的,需要考虑原子操作或临界区保护。 由于代码中使用了多个全局变量,在中断和主程序中同时访问(假设主程序会访问)时,需要防止竞争条件。但用户问题中没有提到,这里先不展开。 因此,修改后的代码可能如下(针对num_的修复和H1翻转的不稳定): 我们引入一个标志位flag1,用于记录junC1是否已经触发过翻转(在junC1>=3000的上升沿触发一次翻转,然后直到junC1<3000时复位标志)。 但是,由于中断服务程序代码不宜过长,我们尽量保持简单。 另一种简单的方法是:在junC1>=3000的条件中,翻转H1后立即改变条件使其不再成立(例如通过改变H2的状态),但原逻辑中H2的改变是在后面的条件中。 或者,我们可以将junC1>=3000的条件改为边沿触发。由于没有硬件支持,我们可以在软件中记录上一次的junC1值。 但是,由于中断服务程序中不能使用太多的静态变量(因为中断可能被嵌套,但51单片机默认中断嵌套需要手动开启,这里假设没有嵌套),我们可以使用静态变量记录上一次的junC1。 修改后的代码(包含num_修复和防止连续翻转): void TM1_Isr() interrupt 3 { static unsigned int last_junC1 = 0; // 静态变量,记录上一次的junC1 // 修复num_:移除原来的赋值,改为在H1==1时自增 // num_ = abs(gyro_z); // 注释掉 // 检查junC1的上升沿:当上次junC1<3000且本次junC1>=3000 if (last_junC1 < 3000 && junC1 >= 3000) { if (H2 == 0) { H1 = !H1; } } last_junC1 = junC1; // 更新last_junC1 if (H1 == 1) { kp *= h; num_++; } if (num_>=300 && H1==1) { H1 = !H1; num_ = 0; H2 = !H2; num1++; } // 对于junC1>=3000且H2==1的情况,我们同样可以用边沿触发?但原逻辑是持续条件,所以这里保持原样? // 原代码:if(junC1>=3000&&H2==1){kp/=h;} // 但注意,这个条件可能会多次执行,导致kp除以h多次?用户可能希望只执行一次? // 同样,我们可以用边沿触发: if (last_junC1 < 3000 && junC1 >= 3000) { // 注意,上面已经更新了last_junC1,所以这里不能再用同样的边沿判断。我们可以分开两个边沿触发变量。 } // 由于上面已经使用了last_junC1,这里我们分开处理,或者合并条件。 // 考虑到代码清晰,我们使用两个静态变量分别记录两个条件的上一次值。 // 但是,由于用户原意是在满足条件时执行kp/=h,而且是在H2==1时,并且条件junC1>=3000持续满足时每次中断都执行?这显然不是用户想要的,因为kp会被连续除以h,导致kp迅速变小。 // 因此,同样需要边沿触发。我们重新设计静态变量: // 改为两个静态变量:分别用于H2==0和H2==1的情况的边沿触发。 // 由于时间关系,我们只处理用户提出的问题,对于第二个条件,用户没有提到问题,但为了稳定,同样建议边沿触发。 // 但是,由于代码已经比较复杂,而且用户只提到H1跳变不稳定,我们先解决H1的问题和num_的问题,其他条件用户可能可以接受? // 先按照只修复num_和H1的连续翻转问题,其他保持不变。 // 最后一句 if (num1>=250) { H2=!H2; } } 但是,上面的修改引入了一个静态变量last_junC1,用于检测junC1的上升沿,从而在上升沿时且H2==0条件下翻转H1。这样,H1就不会在junC1持续>=3000时连续翻转。 另外,对于junC1>=3000&&H2==1的情况,我们还没有修改。为了避免kp被连续除以h,同样应该使用边沿触发。 修改如下: void TM1_Isr() interrupt 3 { static unsigned int last_junC1_0 = 0; // 用于H2==0时的上升沿检测 static unsigned int last_junC1_1 = 0; // 用于H2==1时的上升沿检测 // 第一部分:修复num_不累加 // 注释掉 num_ = abs(gyro_z); // 第二部分:处理junC1>=3000且H2==0的上升沿 if (last_junC1_0 < 3000 && junC1 >= 3000) { if (H2 == 0) { H1 = !H1; } } last_junC1_0 = junC1; // 第三部分:处理H1==1时的操作 if (H1==1) { kp *= h; num_++; } // 第四部分:当num_>=300且H1==1时,复位H1,翻转H2,num1增加 if (num_>=300 && H1==1) { H1 = !H1; num_ = 0; H2 = !H2; num1++; } // 第五部分:处理junC1>=3000且H2==1的上升沿 if (last_junC1_1 < 3000 && junC1 >= 3000) { if (H2 == 1) { kp /= h; } } last_junC1_1 = junC1; // 第六部分:当num1>=250时翻转H2 if (num1>=250) { H2=!H2; } } 这样修改后,两个条件都只在junC1的上升沿触发一次,避免了多次触发。 但是,注意两个静态变量增加了中断服务程序的存储需求。另外,对于51单片机,静态变量是可行的。 最后,关于num_,我们完全去掉了gyro_z的使用,如果用户需要根据gyro_z来做什么,那么可能需要在其他地方使用。但根据用户代码,原来num_被赋值为abs(gyro_z)然后又自增,逻辑不清,所以移除后只自增,符合累计中断次数的意图。 用户需要确认num_的用途。如果用户确实需要使用gyro_z,那么可能需要重新设计。 由于用户问题中只提到H1跳变不稳定和num_不累加,我们针对这两个问题进行了修改。 总结修改: 1. 移除 num_ = abs(gyro_z); 使num_仅在H1==1时自增,用于计数。 2. 对junC1>=3000的条件采用上升沿触发,避免连续触发导致H1不稳定。 3. 同样对另一个条件junC1>=3000且H2==1采用上升沿触发,避免kp被多次除以h。 注意:以上修改假设junC1是一个全局变量,在主循环或其他地方更新。另外,由于中断服务程序执行时间变长,需要评估中断频率是否会导致中断处理时间过长。 建议:如果中断频率很高,尽量减少中断服务程序的处理。 由于没有完整的代码上下文,以上修改仅供参考。用户需要根据实际需求调整。 另外,注意原代码中H2的翻转有两个地方:一个是num_>=300且H1==1时,另一个是num1>=250时。这两个条件可能会相互影响,用户需确保逻辑正确。 最后,请用户测试修改后的代码,观察问题是否解决。 相关问题: 1. 在中断服务程序中,为什么需要避免使用复杂的逻辑或过长的执行时间? 2. 边沿触发和电平触发在中断服务程序中有什么不同? 3. 如何确保在中断服务程序中和主程序中共有的全局变量被安全访问? </think>### 代码问题分析:H1跳变不稳定且num_不累加 #### 1. **`num_`不累加的原因** 问题核心在于**`num_`变量被重复初始化**: ```c num_ = abs(gyro_z); // 每次中断都会覆盖num_的值 if(H1==1){ num_++; } // 自增后又被下一次中断覆盖 ``` - **作用**:每次中断触发时,`num_`都被重置为`gyro_z`的绝对值。 - **冲突**:当`H1==1`时虽然会执行`num_++`,但下一次中断会立即用新的`abs(gyro_z)`覆盖该值。 - **后果**:`num_`无法持续累加,永远达不到条件`num_>=300`,导致后续状态切换失效。 **修复建议**: ```c // 移除初始化,保留自增逻辑 if(H1==1){ kp *= h; num_++; // 纯累加,不再被覆盖 } ``` --- #### 2. **`H1`跳变不稳定的原因** 问题源于**多条件竞争和缺乏状态保护**: ```c if(junC1>=3000 && H2==0) { H1=!H1; } // 条件1 if(num_>=300 && H1==1) { H1=!H1; ... } // 条件2 ``` - **竞争场景**: - 当`junC1>=3000`持续成立时,每次中断都会翻转`H1`(尤其在高速中断场景下)。 - 若`num_`恰好在临界值(如299-300),`H1`可能被两个条件连续修改。 - **后果**:`H1`状态抖动,无法稳定进入`num_>=300`的逻辑分支。 **修复建议**: ```c // 方案:增加状态保护(示例) static bit flag = 0; // 静态标志位 if(junC1>=3000 && H2==0 && !flag) { H1 = !H1; flag = 1; // 锁定条件1 } if(num_>=300 && H1==1) { H1 = !H1; num_ = 0; flag = 0; // 解锁条件1 ... } ``` --- #### 3. **其他潜在问题** - **变量作用域不明确**:`gyro_z`、`junC1`等全局变量可能在主程序/其他中断中被修改,需确认是否需要临界区保护。 - **逻辑冲突**:`H2`翻转同时受`num_>=300`和`num1>=250`控制,可能相互干扰。 - **数值稳定性**:`kp *= h`和`kp /= h`可能因浮点精度或高频中断导致累积误差。 --- ### 修复后代码建议 ```c void TM1_Isr() interrupt 3 { static bit flag = 0; // 状态保护标志 // 修复1: 移除num_初始化,仅保留累加 if(H1==1) { kp *= h; num_++; // 稳定累加 } // 修复2: 增加状态保护 if(junC1>=3000 && H2==0 && !flag) { H1 = !H1; flag = 1; // 锁定条件 } if(num_>=300 && H1==1) { H1 = !H1; num_ = 0; H2 = !H2; num1++; flag = 0; // 解锁条件 } // 其他逻辑保持不变 if(junC1>=3000 && H2==1) { kp /= h; } if(num1>=250) { H2=!H2; } } ``` --- ### 相关问题 1. 中断服务程序中如何安全地操作全局变量? 2. 状态机编程在嵌入式系统中有什么优势和实现要点? 3. 如何检测嵌入式系统中的竞争条件?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值