完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
`````` 本帖最后由 friend0720 于 2016-9-23 10:18 编辑 前言 单片机是一门综合技术,它要求学习者具有一定的电子电路基础,和一定的 C 语言或汇编语言基础。当然如果你学习过《微机原理》那就更好了。C 语言是目前单片机开发最常用到的开发语言,因此请务必学好 C 语言。 同时单片机又是一门实践性很强的技术,如果不亲自动手搭建电路编写程序,是很难真正学会单片机的。下面说说单片机学习的主要过程: 1. 确定一款单片机作为自己的学习目标。目前主流8位单片机有stm8、AVR、PIC等。 2. 搜集该型单片机的各种学习资料。比如书籍、论坛帖子、视频教程等。 3. 下载并搭建软件开发环境 4. 购买硬件开发工具、烧录器、调试器、各种元器件。搭建单片机最小系统,编写程序驱动各种片内资源。 5. 扩展外围电路,并为之编写驱动程序。 后续本人将以ATmega16单片机为例,介绍具体的学习过程。下面是未来我们开发板的大致模样。
送给初学者的一句话:“勿在浮沙筑高台” 遥远的海 (待续) 附件加密!请勿下载! ``````
评分
|
||
相关推荐
715 个讨论
|
||
|
楼主太强大了,学习了
|
|
|
|
|
|
|
|
|
本帖最后由 friend0720 于 2016-2-25 19:13 编辑
第十一节 定时器 Atmega16内部有三个通用定时器计数器:两个8位定时器/计数器:T/C0、T/C2,一个16位定时器/计数器:T/C1。3个通用定时器/计数器除了能够实现通常的定时计数功能外,还具有捕获、比较、脉宽调制输出(PWM)等功能。本节主要介绍T/C0的定时功能。 11.1 Atmega16 定时器计数器的系统组成 外部时钟(16M)经分频器分频后进入到计数器,当计数器益出时就可能引发中断。因此可以通过设置时钟的预分频数以及计数器初值来实现定时功能。 11.2 TIMER0 控制寄存器: TCCR0:预分频寄存器。 TCNT0:计数器。 我们可以通过下面这个公式中算出TCNT0的初值: 其中,Clk为预分频后的时钟频率,Fre为所需定时器的频率。 TIMSK: 中断屏蔽寄存器。 当TOIE0 和状态寄存器的全局中断使能位I 都为”1”时,T/C0 的溢出中断使能。当T/C0 发生溢出,即TIFR 中的TOV0 位置位时,中断服务程序得以执行。 TIFR:中断标志寄存器。 当T/C0 溢出时, TOV0 置位。执行相应的中断服务程序时此位硬件清零。此外, TOV0 也可以通过写1 来清零。当SREG 中的位I、TOIE0(T/C0 溢出中断使能) 和TOV0都置 位时,中断服务程序得到执行。 11.3 程序及说明 /*----------------------------------------------------------------------------------------- 工程: Test系列工程 环境: AVR Studio4.17 + WinAVR2010 设备: Atmega16 作者: 遥远的海 日期: 2015-06-24 说明: 定时器0实验,约250微秒延时。250微秒Atmega16可以执行4000条指令。 ----------------------------------------------------------------------------------------- */ #include #include //--------------------------- //数据类型 //--------------------------- typedef unsigned char U8; //定义8位无符号数 typedef signed char S8; //定义8位有符号数 typedef unsigned int U16; //定义16位无符号数 typedef signed int S16; //定义16位有符号数 typedef unsigned long U32; //定义32位无符号数 typedef signed long S32; //定义32位有符号数 typedef unsigned char * PU8; //定义8位无符号指针 typedef signed char * PS8; //定义8位有符号指针 //--------------------------- //空指令 //--------------------------- #define NOP() __asm("nop") //C 语言中内嵌汇编空指令,起到延时一个指令周期的作用 //--------------------------- //调试用LED 占用PD7(21)脚 //--------------------------- #define LED_BIT 0x80 #define LED_Init() DDRD |= LED_BIT //配置 PD7 口为输出 #define LED_OFF() PORTD&=~LED_BIT //PD7 低电平 LED 灭 #define LED_ON() PORTD|= LED_BIT //PD7 高电平 LED 亮 //--------------------------- //有可能在中断中被改变的变量 //都要加上 volatile 关键字 //--------------------------- volatile U16 g_usDlyCnt=0; //延时周期 //--------------------------- //总中断 //--------------------------- #define EN_INT() sei() //开中断 #define DS_INT() cli() //关中断 //--------------------------- //timer0 //--------------------------- #define CN_TCNT0 194U // 定时器0计数器初值 #define EN_TIMER0() TIMSK |= (1< #define DS_TIMER0() TIMSK &=~(1< /* --------------------------------------------------------------------------------------- 定时器0初始化 外部晶振16MHz 250微秒定时中断 对Timer0来说,这个“定时时间”记录在寄存器TCNT0中。 TCNT0是一个8位寄存器,其寄存器值每过一个预分频时钟周期自加1,当该值达到0xFF后,如果再自加1, 就会产生一个溢出信号,这个溢出信号就是寄存器TIFR中的TOV0,或者称为Timer0的溢出中断标志位。 ----------------------------------------------------------------------------------------- */ void Timer0_Init(void) { TCNT0=CN_TCNT0; // 计数器初值=TCNT0 TCCR0=3; // 预分频为Ck/64 EN_TIMER0(); // TIMSK为定时/计数器的中断屏蔽寄存器, // TOIE0即Timer0的溢出中断使能位 } /* ----------------------------------------------------------------------------------------- Timer0中断处理函数 ----------------------------------------------------------------------------------------- */ SIGNAL(SIG_OVERFLOW0) { if(g_usDlyCnt>0) //延时周期计数 g_usDlyCnt--; else g_usDlyCnt=4000; //4000*250us = 1秒 TCNT0=CN_TCNT0; //重装定时器初值(必须重装) } /* ----------------------------------------------------------------------------------------- 函数: main 功能: C 语言主函数 入口: void 出口: int 备注: 无 ----------------------------------------------------------------------------------------- */ int main(void) { LED_Init(); Timer0_Init(); EN_INT(); //全局中断开 LED_OFF(); //熄灭LED while(1) { if(g_usDlyCnt<2000) LED_ON(); else LED_OFF(); } return 0; } /* ----------------------------------------------------------------------------------------- end of file ----------------------------------------------------------------------------------------- */ “用定时器延时全面代替毫秒级纯软件延时是多任务并行的关键。” "勿在浮沙筑高台" 遥远的海 (待续) |
|
|
|
|
|
|
|
|
本帖最后由 friend0720 于 2016-2-25 19:16 编辑
第十二节 高级定时器之输入捕获与红外解码 上一节我们讲了8位定时器的使用方法,然而Atmega16单片机还有一个更高级的16位定时器T/C1,它具有高精度和宽时范围的特点。本节我们将介绍如何使用T/C1的输入捕获功能,以及如何利用该功能实现NEC红外遥控解码。 12.1 T/C1的输入捕获功能 TCCR1B 是定时器计数器T/C1的一个控制寄存器。当置位标志ICNC1为1时,使能输入捕捉触发信号的噪声抑制功能。输入捕捉信号的触发方式由ICES1位决定,通过边缘检测器进行判断。计数器时钟分频由CS12 CS11 CS10三个位决定。 假定上升沿触发输入捕捉事件,当一个输入捕捉事件发生时,即引脚ICP1上的逻辑电平由低变高时,T/C1的计数寄存器TCNT1的计数值将被T/C1的硬件自动同步复制到捕捉寄存器ICR1中,并置位输入捕获标志位ICF1,产生中断请求。若将连续2次ICR1数据记录下来,那么2次ICR1的差值乘以已知的计数器计数脉冲的周期,就是输入信号一个周期的时间,我们可以利用这一特点来测量外部信号的频率,或测量一段高、低电平的持续时间。 12.2 NEC红外编码 NEC遥控指令的数据格式为:同步码头、地址码、地址反码、控制码、控制反码。 同步码由一个9ms的低电平和一个4.5ms的高电平组成,同步码结束后紧接着发送32位数据(地址码、地址反码、控制码、控制反码均是8位共32位)。560us低电平+1680us高电平(共2.25ms)表示1,560us低电平+560us高电平(共1.125ms)表示 0。 12.3 原理图 红外接收管使用HS0038B 它的管脚顺序与原理图相同。Atmega16的外部事件捕获管脚是PD6脚,因为之前我们用PD6来驱动蜂鸣器,中断那一节HS0038B的OUT脚接在了PD3(INT1)上(原有红外解码驱动是使用中断加定时器实现的),因此电路图需要修改。蜂鸣器改由PC7脚驱动,HS0038B的OUT脚与单片机PD6(ICP1 20 脚)相连。 12.4 红外接收管 HS0038B在开发板上的位置 图上画红圈的地方就是HS0038B. 12.5 程序及说明 /* ----------------------------------------------------------------------------------------- 工程: Test系列工程 环境: AVR Studio4.17 + WinAVR2010 设备: Atmega16 作者: 遥远的海 日期: 2015-06-26 说明: 输入捕获之红外解码 ----------------------------------------------------------------------------------------- */ #include #include //--------------------------- //数据类型 //--------------------------- typedef unsigned char U8; //定义8位无符号数 typedef signed char S8; //定义8位有符号数 typedef unsigned int U16; //定义16位无符号数 typedef signed int S16; //定义16位有符号数 typedef unsigned long U32; //定义32位无符号数 typedef signed long S32; //定义32位有符号数 typedef unsigned char * PU8; //定义8位无符号指针 typedef signed char * PS8; //定义8位有符号指针 //--------------------------- //空指令 //--------------------------- #define NOP() __asm("nop") //C 语言中内嵌汇编空指令,起到延时一个指令周期的作用 //--------------------------- //调试用LED 占用PD7(21)脚 //--------------------------- #define LED_BIT 0x80 #define LED_Init() DDRD |= LED_BIT //配置 PD7 口为输出 #define LED_OFF() PORTD&=~LED_BIT //PD7 低电平 LED 灭 #define LED_ON() PORTD|= LED_BIT //PD7 高电平 LED 亮 //--------------------------- //蜂鸣器 占用 PC7 (29) 脚 //--------------------------- #define BEEP_BIT 0x80 //1< #define BEEP_Init() DDRC |= BEEP_BIT //配置 PD6 口为输出 #define BEEP_OFF() PORTC|= BEEP_BIT //PD6 高电平 蜂鸣器不响 #define BEEP_ON() PORTC&=~BEEP_BIT //PD6 低电平 蜂鸣器响 //--------------------------- //总中断 //--------------------------- #define EN_INT() sei() //开中断 #define DS_INT() cli() //关中断 //------------------------------------------ //红外解码部分 //------------------------------------------ #define NEC_BTN_NONE 0xFF //无按钮被按下 volatile U8 m_ucBtnCode; //控制码 /* ----------------------------------------------------------------------------------------- 红外解码初始化函数 HS0038B OUT脚接M16 PD6(20 ICP1)脚 ----------------------------------------------------------------------------------------- */ void NEC_Init(void) { m_ucBtnCode=NEC_BTN_NONE; DDRD &=~(1< PORTD|= (1< //Bit 7 – ICNC1: 入捕捉噪声抑制器 //Bit 6 – ICES1: 输入捕捉触发沿选择 0下降沿触发,1上升沿触发 //Bit 2:0 – CS1 2:0: 时钟选择 TCCR1B|=0B10000100; //使能输入捕获噪声抑制 //初始设置为下降沿触发 //时钟分频 256 (16M外部时钟下16微秒计数一次) TIMSK|= 1< } /* ----------------------------------------------------------------------------------------- 红外解码输入捕获中断服务函数 定时器1输入捕获中断,计数周期16微秒。 ----------------------------------------------------------------------------------------- */ SIGNAL(SIG_INPUT_CAPTURE1) { static U8 ucStep; //状态机 static U8 ucBitCnt; //记录移位次数 static U8 i,j; //i数组下标,j循环次数 static U8 ucCode[4]; //32位数据 U16 usICR=0; //暂存时间印记 usICR=ICR1; //保存时间印记 switch(ucStep) { //同步码:由一个9ms的低电平和一个4.5ms的高电平组成 case 0: //第一个下降沿到来 TCNT1 = 0; //清零计数器 TCCR1B|=0x40; //上升沿触发 ucStep++; break; case 1: //第一个上升沿到来 TCNT1 = 0; //清零计数器 if(usICR<550 || usICR>570)//测量低电平持续时间(9000us/16us=562.5)是否在误差范围内 goto ERR; TCCR1B&=~0x40; //下降沿触发 ucStep++; break; case 2: //第二个下降沿到来 TCNT1 = 0; //清零计数器 if(usICR<270 || usICR>290) //测量高电平持续时间(4500us/16us=281.25)是否在误差范围内 goto ERR; //同步码有效 TCCR1B|=0x40; //上升沿触发 ucBitCnt=0; //移位次数清零 i=0;j=0; ucStep++; break; //接收32位数据:八位地址码、八位地址反码、八位控制码、八位控制反码: //一个逻辑1传输需要2.25ms(560us低电平+1680us高电平), //一个逻辑0的传输需要1.125ms(560us低电平+560us高电平) case 3: TCNT1 = 0; //清零计数器 TCCR1B&=~0x40; //下降沿触发 if(usICR<30 || usICR>40) //测量低电平持续时间(560us/16us=35)是否在误差范围内 goto ERR; ucStep++; break; case 4: TCNT1 = 0; //清零计数器 if(usICR>100 && usICR<110) //测量高电平持续时间(1685us/16us=105.3125)是否在误差范围内 { //有效数据 1 ucCode=(ucCode<<1)+1; } else if(usICR>30 && usICR<40//测量高电平持续时间(560us/16us=35)是否在误差范围内 { //有效数据 0 ucCode<<=1; } else //干扰信号 goto ERR; //接收完8位数据 if(++j==8) { //接收完32位数据 if(++i==4) { //判断地址码是否正确,注意:(U8)(~ucCode[1])这个写法是必须的 if(ucCode[0]!=(U8)(~ucCode[1])) goto ERR; //判断控制码是否正确 if(ucCode[2]!=(U8)(~ucCode[3])) goto ERR; //记录控制码 m_ucBtnCode=ucCode[2]; TCCR1B&=~0x40;//下降沿触发 ucStep=0; break; } j=0; } TCCR1B|=0x40; //上升沿触发 ucStep=3; break; default: goto ERR; break; } return; ERR: m_ucBtnCode=NEC_BTN_NONE; TCCR1B&=~0x40; //下降沿触发 ucStep=0; } /* ----------------------------------------------------------------------------------------- nec 红外解码按键服务函数 ----------------------------------------------------------------------------------------- */ void NEC_Service(void) { U8 ucBtn=m_ucBtnCode; //当前无键按下 if(NEC_BTN_NONE==ucBtn) return; switch(ucBtn) { case 104: //我的遥控器上 “0”键 LED_ON(); break; case 48: //我的遥控器上 “1”键 LED_OFF(); default: break; } m_ucBtnCode=NEC_BTN_NONE; } /* ----------------------------------------------------------------------------------------- 函数: main 功能: C 语言主函数 入口: void 出口: int 备注: 无 ----------------------------------------------------------------------------------------- */ int main(void) { LED_Init(); NEC_Init(); EN_INT(); //开全局中断 while(1) { NEC_Service(); } return 0; } /* ----------------------------------------------------------------------------------------- end of file ----------------------------------------------------------------------------------------- */ “勿在浮沙筑高台” 遥远的海 (待续)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
本帖最后由 friend0720 于 2016-2-22 12:15 编辑
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
目前板子上的这些东西不到25块钱,不过有些东西买的时候不是只买一个,比如8550三极管50个两块钱。另外需要购买烧录器(20),仿真器(30),万用表(100),烙铁(40),焊锡等等大概要个三百块吧。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
挺不错的教程,每天都过来学一下
|
|
|
|
|
|
|
|
|
谢谢诸位!
|
|
|
|
|
|
|
|
你正在撰写讨论
如果你是对讨论或其他讨论精选点评或询问,请使用“评论”功能。
384 浏览 0 评论
398 浏览 0 评论
405 浏览 0 评论
780 浏览 0 评论
RT-Thread与英飞凌(infineon)合作得板子PSOC 6 板子学习
741 浏览 0 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
17000 浏览 31 评论
/9
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-12-11 20:42 , Processed in 1.002599 second(s), Total 77, Slave 69 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191

淘帖
13528