历史上的今天
返回首页

历史上的今天

今天是:2024年11月04日(星期一)

正在发生

2021年11月04日 | 用关中断和互斥量来保护多线程共享的全局变量

2021-11-04 来源:eefocus

一、使用proteus绘制简单的电路图,用于后续仿真

二、编写程序


/********************************************************************************************************************

---- @Project: Mutex

---- @File: main.c

---- @Edit: ZHQ

---- @Version: V1.0

---- @CreationTime: 20200810

---- @ModifiedTime: 20200810

---- @Description: LED闪烁,蜂鸣器报警

---- 让蜂鸣器在前面3秒发生一次短叫报警,在后面6秒发生一次长叫报警,如此反复循环。 

---- 单片机:AT89C52

********************************************************************************************************************/

#include "reg52.h"

 

/*——————宏定义——————*/

#define FOSC 11059200L

#define T1MS (65536-FOSC/12/1000)   /*1ms timer calculation method in 12Tmode*/

 

#define const_time_05s 400   /*0.5秒钟的时间需要的定时中断次数*/

#define const_time_1s 800   /*1秒钟的时间需要的定时中断次数*/

#define const_time_3s 2400   /*3秒钟的时间需要的定时中断次数*/

#define const_time_6s 4800  /*6秒钟的时间需要的定时中断次数*/

 

#define const_voice_short  100   /*蜂鸣器短叫的持续时间*/

#define const_voice_long   800  /*蜂鸣器长叫的持续时间*/

 

/*——————变量函数定义及声明——————*/

/*定义LED口*/

sbit LED = P3^5;

/*定义蜂鸣器口*/

sbit BUZZER = P2^7;

 

/*LED步骤变量*/

unsigned char ucLedStep=0; 

/*LED统计定时中断次数的延时计数器*/

unsigned int  uiTimeLedCnt=0;

 

/*报警步骤变量*/

unsigned char ucAlarmStep=0; 

/*报警统计定时中断次数的延时计数器*/

unsigned int  uiTimeAlarmCnt=0;

 

/*蜂鸣器鸣叫的持续时间计数器*/

unsigned int  uiVoiceCnt=0;

 

unsigned char ucLock = 0; /* 互斥量,俗称原子锁 */

 

/**

* @brief  定时器0初始化函数

* @param  无

* @retval 初始化T0

**/

void Init_T0(void)

{

TMOD = 0x01;                    /*set timer0 as mode1 (16-bit)*/

TL0 = T1MS;                     /*initial timer0 low byte*/

TH0 = T1MS >> 8;                /*initial timer0 high byte*/

}

/**

* @brief  定时器0中断函数

* @param  无

* @retval 无

**/

void ISR_T0(void) interrupt 1

{

TF0 = 0;  /*清除中断标志*/

  TR0 = 0; /*关中断*/

  if(uiTimeLedCnt < 0xffff)  /*设定这个条件,防止uiTimeCnt超范围*/

  {

      uiTimeLedCnt ++;  /*累加定时中断的次数*/

  }

  if(ucLock == 0) /* 互斥量判断 */

  {

if(uiTimeAlarmCnt < 0xffff)  /*设定这个条件,防止uiTimeCnt超范围*/

{

uiTimeAlarmCnt ++;  /*累加定时中断的次数*/

}

if(0 != uiVoiceCnt)

{

uiVoiceCnt --;

BUZZER = 0;

}

else

{

BUZZER = 1;

}

  }

TL0 = T1MS;                     /*initial timer0 low byte*/

TH0 = T1MS >> 8;                /*initial timer0 high byte*/

  TR0 = 1; /*开中断*/

}

/**

* @brief  外围初始化函数

* @param  无

* @retval 初始化外围

**/

void Init_Peripheral(void)

{

ET0 = 1;/*允许定时中断*/

TR0 = 1;/*启动定时中断*/

EA = 1;/*开总中断*/

 

}

 

/**

* @brief  初始化函数

* @param  无

* @retval 初始化单片机

**/

void Init(void)

{

Init_T0();

LED = 0;

BUZZER = 1;

}

/**

* @brief  LED闪烁函数

* @param  无

* @retval 控制LED闪烁

**/

void Led_Flicker(void)

{

switch(ucLedStep)

{

case 0:

if(uiTimeLedCnt >= const_time_05s) /*时间到,灯亮*/

{

ET0 = 0; /*禁止定时中断*/

uiTimeLedCnt = 0; 

LED = 1;

ucLedStep = 1;/*切换到下一步*/

ET0 = 1; /*允许定时中断*/

}

break;

case 1:

if(uiTimeLedCnt >= const_time_05s) /*时间到,灯灭*/

{

ET0 = 0; /*禁止定时中断*/

uiTimeLedCnt = 0; 

LED = 0;

ucLedStep = 0;/*返回到上一步*/

ET0 = 1; /*允许定时中断*/

}

break;

}

}

/**

* @brief  报警器报警函数

* @param  无

* @retval 报警器报警.

* 保护多线程共享全局变量的原理:

* 多个线程同时访问同一个全局变量,如果都是读取操作,则不会出现问题。如果一个线程负责改变此变量的值,

* 而其他线程负责同时读取变量内容,则不能保证读取到的数据是经过写线程修改后的。

**/

void Alarm_Run(void)

{

switch(ucAlarmStep)

{

case 0:

if(uiTimeAlarmCnt >= const_time_3s) /*时间到*/

{

/* 

* 用关中断来保护多线程共享的全局变量:

* 因为uiTimeAlarmCnt和uiVoiceCnt都是unsigned int类型,本质上是由两个字节组成。

* 在C语言中uiTimeAlarmCnt=0和uiVoiceCnt=const_voice_short看似一条指令,

* 实际上经过编译之后它不只一条汇编指令。由于另外一个定时中断线程里也会对这个变量

* 进行判断和操作,如果不禁止定时中断或者采取其它措施,定时函数往往会在主函数还没有

* 结束操作共享变量前就去访问或处理这个共享变量,这就会引起冲突,导致系统运行异常。

*/

ET0 = 0; /*禁止定时中断*/

uiTimeAlarmCnt = 0; 

uiVoiceCnt = const_voice_short;  /*蜂鸣器短叫*/

ucAlarmStep = 1;/*切换到下一步*/

ET0 = 1; /*允许定时中断*/

}

break;

case 1:

if(uiTimeAlarmCnt >= const_time_6s) /*时间到*/

{

/* 

* 用互斥量来保护多线程共享的全局变量:

* 我觉得,在这种场合,用互斥量比前面用关中断的方法更加好。

* 因为一旦关闭了定时中断,整个中断函数就会在那一刻停止运行了,

* 而加一个互斥量,既能保护全局变量,又能让定时中断函数正常运行,

* 真是一举两得。 

*/

ucLock = 0; /*互斥量加锁。 俗称原子锁*/

uiTimeAlarmCnt = 0; 

uiVoiceCnt = const_voice_long;  /*蜂鸣器长叫*/

ucAlarmStep = 0;/*返回到上一步*/

ucLock = 0; /*互斥量解锁*/

}

break;

}

}

/**

* @brief  延时函数

* @param  无

* @retval 无

**/

void Delay_Long(unsigned int uiDelayLong)

{

   unsigned int i;

   unsigned int j;

   for(i=0;i   {

      for(j=0;j<500;j++)  /*内嵌循环的空指令数量*/

          {

             ; /*一个分号相当于执行一条空语句*/

          }

   }

}

/*——————主函数——————*/

/**

* @brief  主函数

* @param  无

* @retval 实现LED灯闪烁

**/

void main()

{

/*单片机初始化*/

Init();

/*延时,延时时间一般是0.3秒到2秒之间,等待外围芯片和模块上电稳定*/

Delay_Long(100);

/*单片机外围初始化*/

Init_Peripheral();

while(1)

{

/*第一个任务,实现LED闪烁*/

Led_Flicker();

/*第二个任务,实现报警器定时报警*/

Alarm_Run();

}

}

/* 注释一:


* 如何知道1秒钟需要多少个定时中断?


* 这个需要编写一段小程序测试,得到测试的结果后再按比例修正。


* 步骤:


* 第一步:在程序代码上先写入1秒钟大概需要200个定时中断。


* 第二步:基于以上1秒钟的基准,编写一个60秒的简单测试程序(如果编写超过


* 60秒的时间,这个精度还会更高)。比如,编写一个用蜂鸣器的声音来识别计时的


* 起始和终止的测试程序。


* 第三步:把程序烧录进单片机后,上电开始测试,手上同步打开手机里的秒表。


*         如果单片机仅仅跑了27秒。


* 第四步:那么最终得出1秒钟需要的定时中断次数是:const_time_1s=(200*60)/27=444


*/


三、仿真实现

更改蜂鸣器短叫和长叫的时间的宏,可修改相应时间。(proteus蜂鸣器默认12V,可修改为5V,否则不报警)

推荐阅读

史海拾趣

ALTERA(阿尔特拉)公司的发展小趣事

阿尔特拉(Altera Corporation)是一家以可编程逻辑器件(FPGA)和相关技术为主的半导体公司,成立于1983年,总部位于美国加利福尼亚州的圣塔克拉拉。以下是关于阿尔特拉公司发展的五个相关故事:

  1. 创立与早期发展:阿尔特拉公司由Robert Hartmann和Michael Magranet等人于1983年创立,最初致力于设计和制造电可擦除可编程只读存储器(EEPROM)。1984年,公司推出了业界第一个商用FPGA产品,即EP300系列,标志着阿尔特拉在FPGA领域的开创性突破。随后,公司不断扩大产品线,加大研发投入,逐步成为FPGA领域的领军企业之一。

  2. FPGA技术创新:阿尔特拉公司在FPGA技术方面持续进行创新。1992年,公司推出了基于静态随机存储器(SRAM)的FPGA器件,使得FPGA在速度和灵活性方面有了显著提升。此后,阿尔特拉不断推出新的器件系列和工具软件,以满足客户对于性能和可编程性的不断提升的需求。

  3. 与竞争对手的竞争:在FPGA市场,阿尔特拉与Xilinx是两大主要竞争对手。两家公司之间展开了激烈的竞争,包括技术研发、产品性能、市场份额等方面。为了在市场上取得优势,阿尔特拉不断加大研发投入,推出了一系列领先的产品和解决方案,并通过全球销售网络拓展市场。

  4. 收购与合并:阿尔特拉公司在发展过程中进行了多次收购与合并,以扩大市场份额和提升技术实力。2015年,英特尔公司以约160亿美元的价格收购了阿尔特拉,将其并入英特尔旗下成为其子公司。这一收购使得英特尔得以整合阿尔特拉的FPGA技术和产品,进一步巩固了其在半导体行业的地位。

  5. 公司发展与创新:作为英特尔的子公司,阿尔特拉继续致力于技术创新和业务拓展。公司不仅持续改进现有产品的性能和功能,还积极投入到新兴领域的研发与应用,如数据中心、人工智能、物联网等。阿尔特拉通过不断推出创新产品和解决方案,保持了在半导体行业的领先地位。

以上是关于阿尔特拉公司发展的五个相关故事,这些故事展示了阿尔特拉从创立初期到被英特尔收购的发展历程,以及其在FPGA技术领域的技术创新、市场竞争和业务拓展等方面的重要进展。

FTDI公司的发展小趣事

FTDI公司(Future Technology Devices International)在电子行业中的发展充满了多个关键节点和故事,以下是五个相关故事,每个故事均基于事实描述:

1. 创立与早期发展

FTDI公司成立于1992年3月13日,由弗雷德·达特(Fred Dart)创立。起初,公司专注于为个人电脑市场提供服务,其首发产品是针对主板芯片组的解决方案。这些产品被成功应用于IBM的AMBRA和PS/2系列个人电脑上,为当时的计算机技术发展做出了贡献。这一时期的成功为FTDI奠定了坚实的基础,并展示了其在芯片设计领域的初步实力。

2. USB桥接芯片领域的崛起

随着计算机技术的快速发展,FTDI敏锐地捕捉到了USB接口技术的潜力。公司开始专注于USB桥接芯片的研发与生产,并逐渐在这一领域崭露头角。其MM232R和USB-COM232-PLUS1等接口产品因其出色的连接性和兼容性而广受好评。FTDI的USB桥接芯片广泛应用于汽车电子、IOT互联网、工业产品、医疗设备、新能源以及高端消费电子等多个领域,逐步确立了其在全球USB桥接芯片市场的领先地位。

3. 全球化布局与业务拓展

为了进一步扩大市场份额,FTDI积极实施全球化战略。公司在新加坡设立了业务运营总部,并在全球范围内建立了完善的销售和服务网络。这一布局不仅提升了FTDI在全球市场的竞争力,还为其带来了更多的商业机会。同时,FTDI不断拓展产品线,满足不同领域客户的需求,进一步巩固了其在USB桥接芯片领域的市场地位。

4. 并购与合作

在发展过程中,FTDI也通过并购与合作的方式不断壮大自身实力。例如,在2022年,FTDI被电连技术通过发行股份及支付现金的方式收购,成为电连技术的控股子公司。这次并购不仅为FTDI带来了更多的资金和资源支持,还为其未来的发展注入了新的动力。同时,FTDI也与其他行业巨头建立了广泛的合作关系,共同推动电子行业的发展。

5. 技术创新与市场引领

FTDI始终将技术创新作为公司发展的核心驱动力。公司不断投入研发资源,推出具有自主知识产权的新产品和技术解决方案。这些创新成果不仅提升了FTDI的产品竞争力,还为其在全球市场树立了良好的品牌形象。同时,FTDI还积极参与行业标准的制定和推广工作,致力于推动整个电子行业的技术进步和发展。

以上五个故事展示了FTDI公司在电子行业中的发展历程和关键节点。从创立初期的默默无闻到如今的全球领先企业,FTDI凭借其敏锐的市场洞察力、强大的技术实力和不懈的创新精神,在电子行业中书写了属于自己的辉煌篇章。

Alan Industries Inc公司的发展小趣事

随着国内市场的饱和,Alan Industries Inc.开始将目光投向海外市场。公司制定了国际化发展战略,通过设立海外分公司、参加国际展会等方式,积极开拓国际市场。同时,公司还加强了对国际市场的调研和分析,根据不同地区的市场需求和文化特点,推出了针对性的产品和服务。这些努力使得公司在国际市场上也取得了不俗的成绩。

ATOP_Technologies公司的发展小趣事

随着产品线的不断丰富和技术实力的提升,ATOP Technologies开始将目光投向更广阔的市场。公司积极参与国内外各类行业展会和交流活动,加强与同行和客户的交流与合作。同时,ATOP Technologies还积极开展国际合作,与多个国家的知名企业建立了战略合作关系,共同推动工业自动化领域的发展。

HARTING公司的发展小趣事

在追求技术创新的同时,ATOP Technologies也始终注重品质管理和品牌建设。公司通过了ISO-9001认证,从产品的研发设计到生产,所有的流程都严格遵循最佳品质原则。此外,ATOP Technologies还注重品牌形象的塑造和推广,通过参加行业活动、举办技术研讨会等方式,不断提升品牌知名度和影响力。

Automatic Connector公司的发展小趣事

面对日益严重的环境问题,Automatic Connector公司积极响应绿色制造的号召。公司投入大量资金研发环保型电子连接器,采用环保材料和节能工艺,减少生产过程中的污染排放。同时,公司还倡导循环经济的理念,推动废弃电子产品的回收和再利用。这一举措不仅提升了公司的社会形象,也为公司的可持续发展奠定了坚实的基础。

问答坊 | AI 解惑

液晶显示模块编程

MG-12232模块的编程   在系统程序的初始化部分,应对程序中用到的寄存器和临时变量作说明,如: unsigned  char        TRANS; unsigned  char        PAGEADD;&nbs ...…

查看全部问答>

如何诊断和排除电喷发动机加速不良的故障?

一、故障现象。踩下加速踏板后发动机转速不能马上升高,有迟滞现象,加速反应迟缓或在加速过程中发现有轻微的波动。 二、故障原因 (1)点火提前角不正确。 (2)燃油压力过低。 (3)进气系统中有漏气。 (4)节气门位置 ...…

查看全部问答>

开赛后,论坛是否会发布相关解题策略?

本帖最后由 paulhyde 于 2014-9-15 09:03 编辑 如题。。 新手啊~~许多都不会做,希望论坛到时能相助。。 只要能在比赛期间,做出作品,我已经是万分感激了。。 --------------------------------------------soso----------------------------- ...…

查看全部问答>

求助: IDS语音器件分段地址的获取

各位大虾:你们好!上次的帖子问题没说好,重新发一下!!   再下最近在做一个基于单片机的语音播报时钟,但是在语音器件分段地址的获取遇到了问题!主要功能是通过按键播报当前系统时间,我选用的语音芯片是ISD2560,用的AT89S51单片机, ...…

查看全部问答>

wince webservice c#问题

大家好,我创建了一个最简单的hello world webservice,将其添加作为web引用到一个wince应用程序中,调试运行时报参数超出范围异常(argumentoutofrangeexception),报异常语句是:  object[] results = this.Invoke(\"HelloWorld\", ne ...…

查看全部问答>

wince 5.0 播放声音问题

PlaySound(L\"1.wav\",NULL, SND_ASYNC|SND_NODEFAULT ); 看我这句话 有什么错误呢 把1.wav放在了 和exe文件同目录下,但是 为什么 没有播放呢?…

查看全部问答>

招聘信息 企业急需单片机、嵌入式销售、开发、系统工程师以及项目经理

招聘信息 企业急需单片机、嵌入式销售、开发、系统工程师以及项目经理(就职地点北京、青岛、杭州、上海、深圳)      1. 嵌入式企业急需市场销售、软件研发、黑、白盒测试、项目经理等职位,详细资料请登录中华嵌入式人才库 ...…

查看全部问答>

访问DROMSTART之前的地址为什么会FAULT

访问DROMSTART之前的地址为什么会FAULT? 地址是有效的空间,并不是无效的,是我编写的ISP程序的起始地址。 typedef  void (*pFunction)(void); void down_module(void) { u32 JumpAddress;   pFunction Jump_To_I ...…

查看全部问答>

安逸通电子有限公司

公司既述 NET 安逸通国际电子有限公司创建于1990年,总部设立于美国,为了更好服务亚太地区,于2011年迁入中国香港NET 安逸通国际全球最大的后市场持续制造商,是一家为各种商业原始设备制造商 (OEM) 和电子产品制造服务提供商 (EMS) 提供高技术主 ...…

查看全部问答>