mega16上怎么用普通胡地能mega吗I/O口软件模...

温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
如果用弱上拉控制,建议加上拉电阻R1(3.3K~10K),如果不加上拉电阻R1(3.3K~10K),建议R2的值在15K以上,或用强推挽输出。
典型发光二极管控制电路:
&&&&&&&推挽/强上拉口,用拉电流驱动发光二极管
&&& 弱上拉/准双向口,用灌电流驱动发光二极管限流电阻尽量大于1K,最小不要小于470Ω
混合电压供电系统3V/5V器件I/O口互连
&&&&&&&&& 5V单片机连接3.3V器件时,为防止3.3V器件承受不了5V,可将相应的5V单片机I/O口先串一个330Ω的限流电阻到3.3V器件I/O口,程序初始化时将5V器件的I/O口设置成开漏配置,断开内部上拉电阻,相应的3.3V器件I/O口外部加10K上拉电阻到3.3V器件的Vcc,这样高电平是3.3V,低电平是0V,输入输出一切正常。
&&&&&&&&& 3V单片机连接5V器件时,为防3V器件承受不了5V,如果相应的I/O口是输入,可在该I/O口上串接一个隔离二极管,隔离高压部分。外部信号电压高于单片机工作电压时截止,I/O口因内部上拉到高电平,所以读I/O口状态是高电平;外部信号电压为低时导通,I/O口被钳位在0.7V,小于0.8V时单片机读I/O口状态是低电平。
&3V单片机连接5V器件时,为防止3V器件承受不了5V,如果相应的I/O口是输出,可用一个NPN三极管隔离
如何让I/O口上电复位时为低电平
&& 普通8051单片机上电复位时普通I/O口为弱上拉高电平输出,而很多实际应用要求上电时某些I/O口为低电平输出,否则所控制的系统(如马达)就会误动作,现STC12系列单片机由于既有弱上拉输出又有强推挽输出,就可以很轻松的解决此问题。
&& 现可在STC12系列单片机I/O口上加一个下拉电阻(1K/2K/3K),这样上电复位时,虽然单片机内部I/O口是弱上拉/高电平输出,但由于内部上拉能力有限,而外部下拉电阻又较小,无法将其拉高,所以该I/O口上电复位时外部为低电平。如果要将此I/O口驱动为高电平,可将此I/O口设置为强推挽输出,而强推挽输出时,I/O口驱动电流可达20mA,故肯定可以将该口驱动为高电平输出。
PWM输出时I/O口的状态(针对STC系列)
注:参考了宏晶公司的STC12C5A60S2的数据手册
阅读(4593)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'I/O口各种不同的工作模式',
blogAbstract:'&&& 单片机IO口的使用对所有单片机玩家来说都是“家常便饭”,但是你真的了解IO口吗?你真的能按你的需要配置IO口吗?
&&& 一、准双向口输出
&&&&&&& 准双向口输出类型可用作输出和输入功能而不需重新配置口线输出状态。这是因为当口线输出为1时驱动能力很弱,允许外部装置将其拉低。当引脚输出为低时,它的驱动能力很强,可吸收相当大的电流。(准双向口有3个上拉晶体管适应不同的需要)
&&&&& 准双向口读外部状态前,要先锁存为 ‘1’,才可读到外部正确的状态.
& &二、强推挽输出
&&&&&&&& ',
blogTag:'单片机,io口',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:5,
publishTime:5,
permalink:'blog/static/',
commentCount:0,
mainCommentCount:0,
recommendCount:2,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}mega16 同时接GPS模块和RFID模块~mega16一个串口怎么实现?如果不行有什么实现方法?_百度知道中文版_mega16-16L_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
中文版_mega16-16L
上传于||暂无简介
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩327页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢测试座 编程座
(点击图片看大图)
技术资料----
ATmega16L 简介
ATmega16L主要特性如下:
高性能、低功耗的 8 位***R 微处理器
先进的RISC 结构
131 条指令 - 大多数指令执行时间为单个时钟周期
32 个8 位通用工作寄存器
全静态工作
工作于16 MHz 时性能高达16 MIPS
只需两个时钟周期的硬件乘法器
非易失性程序和数据存储器
16K字节的系统内可编程Flash
擦写寿命: 10,000 次
具有独立锁定位的可选Boot 代码区
通过片上Boot 程序实现系统内编程
真正的同时读写操作
512字节的EEPROM
擦写寿命: 100,000 次
1K字节的片内SRAM
可以对锁定位进行编程以实现用户程序的加密
JTAG 接口( 与IEEE 1149.1 标准兼容)
符合JTAG 标准的边界扫描功能
支持扩展的片内调试功能
通过JTAG 接口实现对Flash、EEPROM、熔丝位和锁定位的编程
两个具有独立预分频器和比较器功能的8位定时器/计数器
一个具有预分频器、比较功能和捕捉功能的16位定时器/计数器
具有独立振荡器的实时计数器RTC
8路10 位ADC
8 个单端通道
TQFP 封装的7 个差分通道
2 个具有可编程增益(1x, 10x, 或200x)的差分通道
面向字节的两线接口
两个可编程的串行USART
可工作于主机/ 从机模式的SPI 串行接口
具有独立片内振荡器的可编程看门狗定时器
片内模拟比较器
特殊的微控制器特点
上电复位以及可编程的掉电检测
片内经过标定的RC 振荡器
片内/ 外中断源
6种休眠模式:空闲模式、ADC 噪声抑制模式、省电模式、掉电模式和待机模式以及扩展待机模式
I/O 和封装
32 个可编程的I/O 口
40引脚PDIP 封装, 44 引脚TQFP 封装, 与44 引脚MLF 封装
ATmega16L:2.7 - 5.5V
ATmega16:4.5 - 5.5V
0 - 8 MHz ATmega16L
0 - 16 MHz ATmega16
ATmega16 在1 MHz, 3V, 25℃ 时的功耗
正常模式: 1.1 mA
空闲模式: 0.35 mA
掉电模式: < 1 μA
ATmega16L 参数
ATmega16L存储器
ATmega16L性能参数特性
0-8MHz (ATmega16L)
0-16MHz (ATmega16)
2.7-5.5V (ATmega16L)
4.5-5.5V (ATmega16)
16位定时器 / 计数器
8位定时器 / 计数器
模拟比较器
1(带独立片内振荡器)
硬件乘法器
片内振荡器
引脚电平中断/唤醒功能
ATmega16L封装与引脚数
ATmega16L编程与调试方式
ISP IAP H/PV JTAG
ATmega16L 相关资料
 开发资料
ATmega16L 开发工具
 软件开发平台
 硬件开发平台3066人阅读
图片 懒得 弄了 , 想要的 留下邮箱
STM8单片机的触角----I/O口的应用
4.1 玩转 I/O口必备的“五器”
STM8S208RB单片机的I/O口分布情况如图4-1所示
STM8S208RB管脚分布图
从图4-1中我们可以看到,STM8S208RB共有64个引脚,其中52个通用输入/输出口(GPIO),它们分别是PA1~PA6、PB0~PB7、PC1~PC7、PD0~PD7、PE0~PE7、PF0、PF3~PF7、PG0~PG7、PI0。其中,每个端口都有一个输出数据寄存器(ODR),一个输入引脚寄存器(IDR),一个数据方向寄存器(DDR),一个控制寄存器1(CR1),一个控制寄存器2(CR2),这就是STM8单片机I/O的“五器”。“五器”到手了,该如何使用,如表4-1。
数据方向寄存器
控制寄存器1
控制寄存器2
中断悬浮输入
中断上拉输入
输出(最快速度10MHz)
真正的开漏输出(特定引脚)
I/O口配置表
由表4-1中看出,当Px_DDRn为“1”,Pxn配置为输出,否则为输入。
当配置为输入时,若Px_CR1为“1”,上拉电阻使能,否则为悬浮输入。而Px_CR2为“1”时,开启当前I/O口的外部中断功能,为“0”时关闭外部中断功能。若想读取该I/O引脚上的数据,只需读取相应的Px_IDR寄存器即可。
当配置为输出时,若Px_CR1为“1”,Pxn配置为推挽输出,否则为开漏输出。而Px_CR2为“1”时,当前I/O口的最大输出速率为10MHz,否则最大输出速率为2MHz。想要某个I/O口输出高电平,则向Px_ODR中写入0xff,否则写入0x00;
注:针对STM8S208RB而言,x为A、B、C、D、E、F、G、I;n为0~7。
下面的例子演示了如何设置PB口低四位为推挽输出,最快速度10MHz,并输出高电平,高四位为上拉输入。
/*设置输出高电平*/
PB_ODR = (1 && 3) | (1 && 2) | (1 && 1) | (1 && 0);
/*设置端口方向*/
PB_DDR = (1 && 3) | (1 && 2) | (1 && 1) | (1 && 0);
/*设置推挽输出和定义上拉电阻*/
PB_CR1 = 0
/*设置端口最大速度和关闭中断*/
PB_CR2 = (1 && 3) | (1 && 2) | (1 && 1) | (1 && 0);
/*读取端口输入数据*/
i = PB_IDR & 0xf0;
4.1.1 悬浮与上拉
悬浮输入与上拉输入是两种输入方式,不同之处在于上拉输入时,引脚内部有个上拉电阻。当引脚悬空时,上拉输入的引脚电平是确定的,即高电平;而悬浮输入则不同,它的电平时不确定的,即使外部的一个很小的信号都会使其发生改变。
上拉输入最典型的应用就是外部按键,当按键未按下时,我们要保证它是高电平,当按键按下时才被拉低;而悬浮输入的典型应用就是模数转换,外部的任何一个小信号都要经过A/D采样转换为数字信号。
4.1.2 开漏与推挽
说开漏输出之前,我们先来看看什么是集电极开路输出。
集电极开路
集电极开路输出的结构图如图4-2所示,三极管Q1的集电极就是单片机的I/O口,什么都不接,所以叫做集电极开路。当控制端输入为“0”时,三极管Q2截止,及集电极与发射机之间断开,所以5V电压通过R1接到Q1的基级,Q1导通,即相当于管脚直接接地;当控制端输入“1”时,三极管Q2导通,Q1截止,输出引脚与地之间断开。我们将图4-2简化为图4-3所示。
集电极开路简化图
图4-3中的开关受软件控制,“1”时断开,“0”时闭合。很明显可以看出,当开关闭合时,输出直接接地,所以输出低电平。而当开关断开时,则输出端悬空,即引脚为高阻态。这时电平状态未知,如果后面一个电阻负载(即使很轻的负载)到地,那么输出端的电平就被这个负载拉到低电平了,所以这个电路是不能输出高电平的。
带上拉电阻的开漏输出
图4-4中的10K电阻即是上拉电阻。当开关闭合,输出管脚直接接地,输出为低电平,当开关断开,电流经过10K电阻流入负载,相当于管脚输出高电平。
明白了集电极开路,那么开漏输出就简单了,只要把三极管换成场效应管即可,这样,集电极就变成了漏极,而原理分析是一样的。
开漏输出有这么几个特点:
利用外部电路的驱动能力,减少内部的驱动。当内部导通时,驱动电流是从外部的流经上拉电阻到负载,内部仅需很小的栅极驱动电流。
因为开漏引脚不连接外部的上拉电阻时,只能输出低电平,如果需要同时具备输出高电平的功能,则需要接上拉电阻,很好的一个优点是通过改变上拉电源的电压,便可以改变传输电平。比如加上上拉电阻就可以提供电平输出等。(上拉电阻的阻值决定了逻辑电平转换的沿的速度。阻值越大,速度越低功耗越小,所以负载电阻的选择要兼顾功耗和速度。)
开漏结构提供了灵活的输出方式,但是也有其弱点,就是带来上升沿的延时。因为上升沿是通过外接上拉无源电阻对负载充电,所以当电阻选择小时延时就小,但功耗大;反之延时大功耗小。所以如果对延时有要求,则建议用下降沿输出。
可以将多个开漏输出的引脚连接到一条线上。通过一只上拉电阻,在不增加任何器件的情况下,形成与逻辑关系。这也是,等总线判断总线占用状态的原理。
我们同样以三极管为例,来看看推挽输出的结构,如图4-5所示。
输入端由软件控制,当软件写“1”时,输入高电平,三极管Q1导通,Q2截止;当软件写“0”时,输入低电平,三极管Q1截止,当输出端的电平高于0.7V时,Q2导通。我们可将上面电路图简化为图4-6所示。
推挽输出简化图
当软件写“1”时,开关S1闭合,S2断开,VCC连接到引脚上,输出高电平;当软件写“0”时,开关S1断开,S2闭合,引脚接到GND,输出低电平。
4.2 LED孤独的闪着
在点亮小灯之前我们先来了解一下LED的一些基础知识,图4-7是普通发光二极管的外形图及电路符号,长脚为阳极。我们其实也可以看二极管里面大片的一侧是阴极,但是也有些***LED是相反的。
LED硬件结构
闪烁LED电路图
图4-8是闪烁LED的电路原理图,PB0口通过一个330Ω电阻连接发光二极管的阴极,即低电平LED亮,高电平灭。
程序代码如下。
#include &stm8s208r.h&
/***************函数声明***************/
void delay(unsigned int time);
/***************主函数*****************/
int main(void)
&&& PB_DDR |= 0x01; //选择输出模式
&&& PB_CR1 |= 0x01; //推挽输出模式
&&& PB_CR2 |= 0x00; //低速输出模式
&&& while (1)
&&&&&&& PB_ODR &= 0& // 小灯亮
&&&&&&& delay(50000);
&&&&&&& PB_ODR |= 0x01;& //小灯灭
&&&&&&& delay(50000);
/************延时子程序************************/
void delay(unsigned int time)
&&& while(time--);&&&&&
老大,这个程序不算难,原理我都懂.就是先把IO口的工作方式等都设置好,然后给小灯一个低电平,小灯就亮,然后延时一会,再给小灯一个高电平,小灯就灭,再延时.如此反复,就会有闪烁的效果.但是问题是为什么给管脚赋值的时候要用”与等于”和”或等于”呢?我就是理解不了这个.
放心,作为老大.我一定不会让你受苦!Relax.Everything is OK.这种赋值方法.无论是“与等于”或者“或等于”,目的都是在改变某一位或者某几位的电平的同时,保持剩余位置的电平不变.
因为进行“与”运算的时候.无论1或者0“与”1后得到的结果没有发生改变(还是1或者0).当进行“或”运算的时候,无论1或者0“或”0后得到的结果也没有发生改变(还是1或者0).讲到这里.应该能明白其中的道理了吧?很简单.当你需要对某位置高的时候就“或”1,需要保持原来的电平的位置,则“或”0.当需要对某位置低的时候就“与”0,需要保持就“与”1这就通过程序达到了“位操作”的效果.
Come on baby.Go on reading the most important paragraph!
1.注意,这里的位操作并不是真正意义的位操作.要注意区分两者的本质区别!
2.虽然在本例中不使用这种赋值方法,直接赋值的话对程序不会造成任何影响.但是养成一个好的习惯对以后的进一步学习非常有好处,因为以后程序代码量增加之后,此类这种位操作,经常出现,如果不养成这种习惯,会很难以找出程序中的错误.对调试程序产生极大的影响.既费时又费力.所以极力推荐大家使用这种方法
4.3 跑马灯是怎么跑的?
4.3.1 应用switch-case语句设计跑马灯
大家在前面一节初步的接触了单个IO口寄存器设置及其使用方法,在本节我们来用PB的8个I/O口来进行跑马灯的程序设计。
我们简单的回顾一下switch-case的用法。如图4-9所示,switch相当于开关的拨口,i选择被连端口,case相当于开关的被连端口,当i为某值时,则有且只导通该路case i。
跑马灯的电路原理图如图4-10所示.
switch-case示例图
跑马灯电路原理图
程序代码如下。
#include&stm8s208r.h&&& //& 开始时的头文件包含
/***************函数声明***************/
void delay(unsigned int time);&& //声明延时函数
/***************主函数*****************/
Into main(void)
&&& unsigned char i = 0;&&&
&&& PB_DDR = 0XFF;&&&&& //设置IO口B为输出
&&& PB_CR1 = 0XFF;&&&&& //设置IO口B为推挽方式
&&& PB_CR1 = 0X00;&&&&& //输出最快速度为2MHz
&&& PB_ODR = 0XFF;&&&&& //设置输出寄存器的输出数值,初始化小灯全灭
&&& while (1)
&&&&&&& switch (i)&&&&&&& //让小灯从低位到高位依次亮
&&&&&&&&&&& case 0:& PB_ODR = 0XFE;
&&&&&&&&&&&&&&& && Delay(40000);&&&&& //延时约20mS
&&&&&&&&&&&&&&& && i++;&&&&&&&&&&&&& //让i加1下次执行程序时进入到case 2
&&&&&&&&&&&&&&& &&&&&&&&&&&&& //跳出case 0,重新到switch处检查i值
&&&&&&&&&&& case 1:& PB_ODR = 0XFD;
&&&&&&&&&&& &&&&&& Delay(40000);
&&&&&&&&&&&&&&& && i++;
&&&&&&&&&&&&&&& &&&&&&&&&&&&
&&& &&&&&&& case 2:& PB_ODR = 0XFB;
&&&&&&&&&&& &&&&&& Delay(40000);
&&&&&&&&&&&&&&& && i++;
&&&&&&&&&&&&&&& &&&&&&&&
&&&&&&&&&&& case 3:& PB_ODR = 0XF7;
&&&&&&&&&&& &&&&&& Delay(40000);
&&&&&&&&&&&&&&& && i++;
&&&&&&&&&&&&&&& &&&&
&&&&&&&&&&& case 4:& PB_ODR = 0XEF;
&&&&&&&&&&& &&&&&& Delay(40000);
&&&&&&&&&&&&&&& && i++;
&&&&&&&&&&&&&&& &&&&&&&&
&&&&&&&&&&& case 5:& PB_ODR = 0XDF;
&&&&&&&&&&& &&&&&& Delay(40000);
&&&&&&&&&&&&&&& && i++;
&&&&&&&&&&&&&&& &&&&&&&&
&&&&&&&&&&& case 6:& PB_ODR = 0XBF;
&&&&&&&&&&& &&&&&& Delay(40000);
&&&&&&&&&&&&&&& && i++;
&&&&&&&&&&&&&&& &&&&&&&&
&&&&&&&&&&& case 7:& PB_ODR = 0X7F;
&&&&&&&&&&& &&&&&& Delay(40000);
&&&&&&&&&&&&&&& && i = 0;
&&&&&&&&&&&&&&& &&&&
&&&&&&&&&&& default : PB_ODR = 0XFF;
&&&&&&&&&&& &&&&&& Delay(40000);
/************延时子程序************************/
void delay(unsigned int time)
&&& while (t--);&&&&&&&&&&&&& //让while执行t次空程序达到延时的目的
我说老大呀我又懵了,上面的程序里IO口必须设置为推挽输出吗?速度就只能设置为最快2MHz吗?
懵啥呀有我在不用怕,其实它还可以设置为开漏方式,即PB_CR1 = 0x00,小灯是低电平点亮,电路图中我们在小灯正极外接了电源在这种情况下开漏与推挽两者的灌电流都很大所以没有什么区别,具体参考本章第一节,除此之外,还可以设置最快速度10MHz,即PB_CR2 = 0XFF。为了程序的规范编写,在定义函数时要完整,如unsigned char Delay(unsigned char t),如果在没有返回值时,前面最好加void,括号内没有定义行参时也定义void,如void
Delay(void)。在写每个case时,一定不要忘了在相应的case语句后加跳出语句break,否则会接着执行下个case语句。
4.3.2 用for循环遛马
硬件电路图与图4-10一样。
初级骑马技巧代码如下。
#include&stm8s208r.h&&&&& //包含stm8头文件
/***************函数声明***************/
void delay(unsigned int x);&& //延时函数
/***************主函数*****************/
&&& PB_DDR=0&&&&& //I/O口初始化,将PB口设为输出状态
&&& PB_CR1=0&&&&& //PB口(CR1)置1推挽输出
&&& PB_CR2=0X00;&&&&& //CR2置0低速模式,初始化完成
&&& PB_ODR = 0XFE;&&& //低电平有效,点亮第一个LED
&&& while (1)&&&&&&&&
&&&&&&& PB_ODR = 0XFE;&&&&& //赋初值配合for循环使用
&&&&&&& for(i=0;i&8;i++)
&&&&&&&&&&& delay(50000);&&&&
&&&&&&&&&&& PB_ODR &&= 1;&&&& //左移一位,点亮下一个LED
&&&&&&&&&&& PB_ODR |= 0x01;&& //左移后最低位自动补0,故将最低为置高
/************延时子程序************************/
void delay(unsigned int x)&&&&&&
& while(x--);
4.4 数组与万能流水灯
利用数组让你腾云驾雾但需要反复磨练方能修成正果,原理图等同上节马圈,下面是你期待已久的至高技能。
#include &stm8s208r.h&&&&&&&&&&&&& &&//包含头文件使软件识别特殊寄存器像PB_DDR等
/**************定义一个二维数组************/
/*装入使小灯花样闪亮的数据&&&&&&&&&&&&&&& */
/******************************************/
unsigned char dis[5][8]=
{0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f},
{0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe},
{0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff},
{0x7f,0x3f,0x1f,0x0f,0x07,0x03,0x01,0x00},
{0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f}
/***************函数声明***************/
void GPIO_Init(void);&&&&&&&&& &&&& // GPIO口的初始化子程序
void display(void);&&&&&&&&&&& &&&& // 用PB口显示花样小灯子程
void delay(unsigned int time) ;& &&&// 延时子程序
/***************主函数*****************/
int main(void)
& GPIO_Init();&&&&&&&&&& //端口初始化
& while(1)&&&&&&&&&&&&&&& //死循环
&&& display();&&&&&&&&&& //始终让小灯显示花样
/**************GPIO口的初始化*****************/
void GPIO_Init(void)
&PB_ODR=0&&&&&& &//初始使小灯全灭
&PB_DDR=0&&&&&&& //DDR为0是输入,1是输出。此处为PB的8个端口均为输出
&PB_CR1=0&&&&&&& //推挽输出模式
&PB_CR2=0x00;&&&&&& //低速输出模式
/************小灯花样显示子程序***************/
void display(void)
&&& unsigned char i,j;
&&& for(i = 0; i & 5; i++)&&&&&&&& //循环二维数组的行数
&&&&&&& for(j = 0; j & 8; j++)&&&&&&& //循环二维数组每行中的数据
&&&&&&&&&&& PB_ODR = dis[i][j];&& //把数据给PB口使小灯显示&&&&&&&
&&&&&&&&&&& delay(50000);
/************延时子程序************************/
void delay(unsigned int time)
&& while(time--);
4.5 考验STM8的“臂力”
STM8推挽输出能力很强,我们就用数码管来检验一下STM8的“ 臂力”。
4.5.1 STM8直接驱动一个数码管
数码管是一种最常见的显示器件,可以显示一个8字型的数字,其内部其实是由8个发光二极管组成,每个发光二极管称为一个字段,分为a、b、c、d、e、f、g、dp八段,其中dp为小数点,有共阴极和共阳极两种形式。下面我们就以共阳极的数码管为例作具体讲解。
我们来做一个实验:用STM8直接驱动一个数码管,让数码管显示数字0-9。
硬件电路设计如图4-11。
STM8点亮一个数码管电路图
程序代码如下。
#include &stm8s208r.h&
/* --------&& 函数声明& ------------*/
void delay(unsigned int delay_time);&
void display_SMG(void);
/* SMG_table&& 共阳数码管段选编码*/
unsigned char SMG_table[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
/* 对应显示数字&&&&&&&&&&&&&& 0 , 1, 2,& 3,& 4,& 5,& 6,& 7,&& 8,&& 9& */
{&&&& /*端口初始化-------------------------------------------------*/
PB_DDR = 0XFF; //定义PB口为输出,用于控制数码管段选
PB_ODR = 0XFF; //定义PB初始输出为高,数码管初始不亮
PB_CR1 = 0XFF; //定义推挽输出
PB_CR2 = 0XFF; //定义快速输出
/*-----------------------------------------------------------*/
&display_SMG(); //用一个数码管显示数字
/* 数码管显示函数 */
void display_SMG(void)&&
/*用一个数码管显示 0--9 */
&for(i = 0; i & 10; i++)&
PB_ODR = SMG_table[i];
delay(50000);&&&&&&
/* 延时函数 */
void delay(unsigned int delay_time)
while (delay_time != 0)
delay_time--;
程序分析:
共阳极数码管,顾名思义,就是公共端接到阳极(正极),改变另一端的电平高低来控制其各个段的亮灭,不同的亮灭组合就出现了不同的数字。程序中的SMG_table就是一个存放0~9亮灭组合的数组。用for语句循环十次,显示数字0~9。这里要注意的是,在显示一个数字时,必须保持其亮一段时间,如果数字的变化太快则肉眼无法识别,只能看到一个8字。
4.5.2 STM8驱动8个数码管显示生日
之前,我们用8个I/O口引脚控制了1个数码管的显示,那我们想控制8个数码管,是不是要用64个I/O口引脚呢?当然不是啦,教你一招,用16个引脚和8个三极管就能控制8个数码管。如图4-12【所示。
数码管动态显示8个数码管
我这一招的秘诀其实是利用了人眼的“视觉暂留”效应实现的。原理是用PB口控制数码管显示显示的内容,用PG口控制哪个数码管亮,其实任意时刻只有一个数码管在亮,一个灭了另一个再亮,这样轮回显示。当数码管的亮灭达到一定频率时,肉眼无法识别,认为8个数码管一起亮的,这就是动态显示。这里的三极管起到了两个作用,一是放大作用,二是开关作用。用PG口控制三极管的通断,导通的三极管对应的数码管有电流流过,就能发亮显示,并且将电流放大,将一个管脚的输出电流放大提供给1个数码管中的8段led发光。
程序代码:
#include &stm8s208r.h&
/* --------&& 函数声明& ------------*/
void delay(unsigned int delay_time);&
void display_SMG(void);
/* SMG_table&& 共阳数码管段选编码*/
unsigned char SMG_table[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
/* 对应数码管显示数字&&&&&&&&& 0 ,& 1,& 2,& 3,& 4,& 5,& 6,& 7,& 8,& 9 */
{&& /*端口初始化-------------------------------------------------*/
&&& &PB_DDR = 0XFF; //定义PB口为输出,用于控制数码管段选
&&& &PB_ODR = 0XFF; //定义PB初始输出为高,数码管初始不亮
&&& &PB_CR1 = 0XFF; //定义推挽输出
&&& &PB_CR2 = 0XFF; //定义快速输出
&&& &PG_DDR = 0XFF; //定义PG口为输出,用于控制数码管位选
&&& &PG_ODR = 0XFF; //定义PG初始输出为高,数码管初始不亮
&&& &PG_CR1 = 0XFF; //定义推挽输出
&&& &PG_CR2 = 0XFF; //定义快速输出
&&& &/*-----------------------------------------------------------*/&&&
&&& &while (1)
&&& && display_SMG(); //用数码管显示数字
/* 数码管显示函数 */
void display_SMG(void)
{&& /* 第8个数码管显示2 */
&&& &PB_ODR = SMG_table[2];&&&&&&& //段选,让全部数码管显示2
&&& &PG_ODR = 0X7F;&&&&&&&&&&&&&&& //位选, 让第8个数码管亮
&&& &delay(500);&&&
&&& &/* 第7个数码管显示0 */
&&& &PB_ODR = SMG_table[0];&&&&&&& //段选,让全部数码管显示0
&&& &PG_ODR = 0XBF;&&&&&&&&&&&&& &&//位选, 让第7个数码管亮
&&& &delay(500);&&&
&&& &/* 第6个数码管显示1 */
&&& &PB_ODR = SMG_table[1];&&&&&&& //段选,让全部数码管显示1
&&& &PG_ODR = 0XDF;&&&&&&&&&&&&&&& //位选, 让第6个数码管亮
&&& &delay(500);&&&
&&& /* 第5个数码管显示1 */
&&& &PB_ODR = SMG_table[1];&&&&&&& //段选,让全部数码管显示1
&&& &PG_ODR = 0XEF;&&&&&&&&&&&&&&& //位选, 让第5个数码管亮
&&& &delay(500);
&&& &/* 第4个数码管显示0 */
& PB_ODR = SMG_table[0];&&&&&& //段选,让全部数码管显示0
&&& &PG_ODR = 0XF7;&&&&&&&&&&&&&&& //位选, 让第4个数码管亮
&&& &delay(500);&&&
&&& &/* 第3个数码管显示1 */
&&& &PB_ODR = SMG_table[1];&&&&&&& //段选,让全部数码管显示1
&&& &PG_ODR = 0XFB;&&&&&&&&&&&&&&& //位选, 让第3个数码管亮
&&& &delay(500);&&&
&&& &/* 第2个数码管显示1 */
&&& &PB_ODR = SMG_table[1];&&&&&&& //段选,让全部数码管显示1
&&& &PG_ODR = 0XFD;&&&&&&&&&&&&&&& //位选, 让第2个数码管亮
&&& &delay(500);&&&
&&& &/* 第1个数码管显示0 */
&&& &PB_ODR = SMG_table[0];&&&&&&& //段选,让全部数码管显示0
&&& &PG_ODR = 0XFE;&&&&&&&&&&&&&&& //位选, 让第1个数码管亮
&&& &delay(500);
/* 延时函数 */
void delay(unsigned int delay_time)
& while (delay_time != 0)
&&& delay_time--;
程序分析:
与一个数码管显示不同,显示8个数码管不仅有段选(即显示的内容),还有位选(即选择让哪个数码管亮),位选和段选配合使用,每个数码管亮的内容都是相同的,每次只让一个数码管亮,一个数码管灭了之后另一个马上亮,同时显示内容发生变化,依次由右向左亮灭,这样8个数码管跑起来了。值得注意的是,这里的延时delay(500)不应太长,不宜太短,若延时太长,数码管显示看起来就是一个一个分别亮的,不能达到同时亮的效果。如果延时太短,数码管显示就会很暗,效果不好。
4.6 独立按键的应用
独立按键在单片机中应用非常广泛,用按键输入信息,数码管显示信息,是最简单的一种人机交互方式。
STM8输入总共有4种输入方式,分别是:上拉输入,中断上拉输入,悬浮输入,中断悬浮输入。我们在检测按键时,为了得到稳定的电平,需要用上拉电阻,我们可以通过程序设置启用芯片内部的上拉电阻,也可以设置为悬浮输入,然后接外部上拉电阻。表4-2为STM8输入方式配置表。
数据方向寄存器
控制寄存器1
控制寄存器2
中断悬浮输入
中断上拉输入
输入模式配置
4.6.1 启用内部上拉检测按键状态
接下来我们就设计一个实验,用一个按键控制数码管显示数字的变化,当PE0所接的独立按键按下时,数码管中显示的数字加1,显示0~9范围的数字。
硬件电路:
图4-13启用内部上拉电阻时接独立按键
程序代码如下:
#include &stm8s208r.h&
/* --------&& 函数声明& ------------*/
void delay(unsigned int delay_time);&
void display_SMG(void);
void key_press(void);
/*----------------------------------*/
/* SMG_table&& 共阳数码管段选编码*/
unsigned char SMG_table[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
/* 对应显示数字&&&&&&&&&&&&&& 0, 1,& 2,& 3, &4,&& 5,&& 6,& 7,& 8,& 9 */
unsigned char N //显示的数字
&&& /*端口初始化-------------------------------------------------*/
&&& &PB_DDR = 0XFF;& //
定义PB口为输出,用于控制数码管段选
&&& &PB_ODR = 0XFF;& //
定义PB初始输出为高,数码管初始不亮
&&& &PB_CR1 = 0XFF;& //
定义推挽输出
&&& &PB_CR2 = 0XFF;& //
定义快速输出
&&& &PE_DDR &= 0XFE; //
定义PC口为输入,检测按键输入
&&& &PE_CR1 |= 0X01; //
定义为上拉输入,芯片内部启用上拉电阻
&&& &PE_CR2 &= 0XFE; //
定义不使能中断
&&& /*-----------------------------------------------------------*/
&&& while (1)
&&& &key_press();&& //用查询法判断按键是否按下
&&& &display_SMG(); //用数码管显示Number值
/* 按键处理函数 */
void key_press()
&&& &/* 判断按键是否按下 */
&& if((PE_IDR & 0x01) == 0)
&&&&&&& &delay(13000);&&&&&&&&&&&& //延时10--20ms 去除抖动
&&& if((PE_IDR & 0x01) == 0) //再次判断按键是否按下,若按下,Number+1
&&&&&&& && {
&&&&&&&&&&& & if(Number & 9)&&&&&&
& &&&&&&&&& Number++;
&&&&&&&&&&& & else
&&&&&&&&& &&&&&Number = 0; &&&&&&&&&&&& &
&&&&&&& &&& }
/* 数码管显示函数 */
void display_SMG(void)&&
&&& /*用一个数码管显示 Number */
&&& PB_ODR = SMG_table[Number];
/* 延时函数 */
void delay(unsigned int delay_time)
& while (delay_time != 0)
&&& delay_time--;
程序分析:
这个程序就是在之前用一个数码管显示数字的基础上加了独立按键控制显示内容,注意端口初始化中PE0口的配置,PE_DDR &= 0XFE,设置PE0为输入方式,PE_CR1 |= 0X01,设置PE0为启用上拉电阻,PE_CR2 &= 0XFE,设置PE0 为不使用中断。当没有按键按下时,PE0口检测到高电平,if((PE_IDR & 0x01) == 0)不成立,若按键按下,PE0口检测到低电平,条件成立,执行相应操作(即显示数字加1)。在key_press()函数里,做两次if判断和延时10~20ms的目的是去除抖动干扰。
4.6.2 浮空+外部上来检测按键状态
刚才我们设置了上拉输入方式,现在我来试一下浮空输入方式。
将前面用上拉方式接独立按键的程序稍加修改,只需在端口初始化时,将PE的端口的配置方式改一下即可。
/*端口初始化-------------------------------------------------*/
&&& PB_DDR = 0XFF;& // 定义PB口为输出,用于控制数码管段选
&&& PB_ODR = 0XFF;& // 定义PB初始输出为高,数码管初始不亮
&&& PB_CR1 = 0XFF;& // 定义推挽输出
&&& PB_CR2 = 0XFF;& // 定义快速输出&
&&& PE_DDR &= 0XFE; // 定义PE口为输入,检测按键输入
&&& PE_CR1 &= 0XFE; // 定义为浮空输入,需要外部接上拉电阻
&&& PE_CR2 &= 0XFE; // 定义不使能中断
&&& /*-----------------------------------------------------------*/
更改了程序,我们重新下载,实验一下,在配置浮空方式并且外部没有启用上拉电阻的情况下,独立按键非常不稳定,不能正确的反应按键的状态。这时候我们就需要外加上拉电阻使PE0得到稳定的电平。如图 4-14所示
悬浮输入外部加上拉电阻
在原先浮空输入的基础上,PE0引脚接了10k的上拉电阻。当没有按键按下时,PE0引脚因为有上拉而得到高电平,当按键按下时,PE0和GND相连得到低电平。我们通过外部自己加上拉电阻,将原本浮空、不确定电平的引脚变成了确定的高电平或者低电平,保证了按键的可靠性和稳定性。
对比总结:
经过“上拉输入”和“浮空输入”的对比实验,我可以得出结论:上拉输入可以使引脚在不接任何东西的状态下得到确定的电平,而浮空输入在不接任何东西的情况下电平不确定,在接按键或者一些其他需要判断引脚高低电平的场合,最好启用内部上拉电阻。
4.7 使用固件库点亮神灯
4.7.1 什么是固件库
“世界因懒人而变化!”人们因为懒得走路而发明了汽车,因……而……,因……而……,因懒得直接操作寄存器而制作的固件库。
每初始化一个I/O口就需要操作相应的DDR、CR1、CR2寄存器,使用的时候就需要操作ODR、IDR寄存器,有没有办法简化一些呢?有,那就是编写一个函数,每次想用I/O口的时候就调用这些函数,当这样的函数编多了,组合起来,就成了固件库。固件库一般由芯片生产厂商提供。
接下来,我们就看看意法半导体为STM8s做的固件库(下载地址:)
文件“stm8s_fwlib_um.chm”是库函数的帮助文件,“version.txt”是版本信息,文件夹“FWLib”下面又有三个文件夹:“examples”中包含的是各功能模块的例子,“library”中包含的就是今后要用到的库了,“project”则包含了一个例子工程。
4.7.2 建立第一个包含库的工程
第一步:按常规方法建立空工程。
第二步:复制“library”文件夹复制到前面的工程文件夹中,复制“project”文件夹中的“main.c”、“stm8s_conf.h”到工程文件夹中。
第三步:在“Source Files”上点右键,选择“Add Files to Folder...”选择“library\src”中的“stm8s_gpio.c”。
第四步:选择“Project”下的“Settings...”或使用快捷键“Shift+F7”打开“Project Settings”对话框,选择“C Compiler”选项卡,如图选择“Preprocessor”,在出现的页面中添加路径“library\inc”,如图所示。
完成:点击编译或快捷键F7,出现“0 error(s), 0 warning(s)”就成功了!
4.7.3 重新点亮神灯
工程建立好了,让我们重新点亮神灯吧。
首先,在工程列表的“External Dependencies”文件夹中,打开“stm8s.h”确定第45行的“#define STM8S208”未注释。
45& #define STM8S208
46& /* #define STM8S207 */
47& /* #define STM8S105 */&
48& /* #define STM8S103 */
接着,打开“stm8s_conf.h”,去掉第80行的“#define _GPIO (1) ”的注释。
79& /*********************************** GPIO *********************************/
80& #define _GPIO (1)
82& /*********************************** I2C **********************************/
83& /* #define _I2C& (1) */
去掉“main.c”文件的只读属性,下面就开始编写主程序。
#include &stm8s.h&
void delay(unsigned int time);
void main(void)
&&& /* 设置PB0为推挽高速输出,初始值为高电平 */
&&& GPIO_Init(GPIOB, GPIO_PIN_0, GPIO_MODE_OUT_PP_HIGH_FAST);
&&& while (1)
&&&&&&& /* 置低PB0,点亮LED */
&&&&&&& GPIO_WriteLow(GPIOB, GPIO_PIN_0);
&&&&&&& delay(50000);
&&&&&&& /* 置高PB0,熄灭LED */
&&& &&& GPIO_WriteHigh(GPIOB, GPIO_PIN_0);
&&&&&&& delay(50000);
void delay(unsigned int time)
&&& while(time--)
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:11458次
排名:千里之外
评论:12条
(1)(1)(1)(1)(2)(1)(1)(3)(1)

参考资料

 

随机推荐