PIC单片机I-O口单线通讯的实现
- 格式:doc
- 大小:50.00 KB
- 文档页数:3
pic单片机io口控制教程之c语言编程实现1、什么是I/O?I/O能做什么?I/O控制对于单片机而言是最基础最核心的东西,其实单片机除了AD DA 转换之外的事情。
其他大部分的事情I/O口都能做的到。
I/O 控制简单却能千变万化。
I/O就是Input/Output的英文简写,意译为输入/输出。
I/O对于单片机是最基本的东西,单片机除了AD、DA转换之外的事情,大部分I/O都可以做到。
如果你是刚刚步入电子的新手,那你最好要知道一下I/O口具体能做什么。
感性的认识对你的学习是很有帮助的。
I/O口输出一个高(低)电平可以用来点亮一个LED灯,可以接通过一个继电器,来开启电机,来开启音响。
开启许多的东西,也可以用于通信等等。
输入一个高(低)电平可以用来检测按键,检测红外线输入,检测信号等等。
2、TRISA寄存器与io口之间的对应关系:首先看下一个芯片的原理图。
注意RA5~RA0这些口在看看RA口的方向控制寄存器TRISA在看看RA口的数据控制寄存器PORTA可以看出芯片原理图中的第二脚RA5 口和TRISA 寄存器中的TRISA5位对应和PORTA寄存器中的RA5位对应的,RA4~RA0都是如此对应的。
也就是说TRISA 寄存器中的TRISA5位和PORTA寄存器中的RA5位来控制第二脚的RA5口。
3、如何控制I/O口?其实控制单片机,就是控制寄存器上的各个位,设置成高设置成低。
就好像给你一台机器有8个的按钮。
然后你根据说明书上介绍,根据你的需要按下或者松开相应的按键来得到你想得到的功能。
只不过我们用的不是手而是C语言来按下和松开这些按键。
TRISA寄存器是方向控制寄存器。
就是控制I/O输入还是输出。
比如TRISA寄存器中的TRISA5位设置成为0 RA5口是输出设置成为1 RA5口为是输入。
4、C语言的具体实现:。
一种基于PCI总线与PIC单片机通信的实现方法
谭湘宇;刘晓东
【期刊名称】《电讯技术》
【年(卷),期】2004(44)5
【摘要】基于PCI总线实现各种数据通信、数据采集以及状态控制已得到广泛的应用.本设计在遵循PCI总线原理下,利用CPLD中I/O资源丰富、用户可自定制逻辑的优势,应用Verilog HDL语言完成对PCI总线接口芯片的设计与实现,并通过接口芯片实现PIC单片机与上层应用程序的通信任务,完成各项控制命令.
【总页数】4页(P171-174)
【作者】谭湘宇;刘晓东
【作者单位】电子科技大学,电子工程学院,四川,成都,610054;中国西南电子技术研究所,四川,成都,610036
【正文语种】中文
【中图分类】TN919
【相关文献】
1.基于PIC16F73单片机和ADS8341的SPI通信软硬件实现方法 [J], 党瑞荣;苗强
2.基于PIC16F73单片机和ADS8341的SPI通信软硬件实现方法 [J], 苗强;党瑞荣
3.简析基于PIC32单片机的CAN总线通信 [J], 王越;胡宇
4.一种PCI总线ARINC429通信卡实现方法 [J], 李辉;黄敬礼
5.u'nSP16位单片机与PIC8位单片机基于CAN总线的通信实现 [J], 王兴贵;房伟;李楠
因版权原因,仅展示原文概要,查看原文内容请购买。
基于PIC单片机的软串口的实现Ξ程 频1) 高 伟2)(中南民族大学计算机学院1),武汉数字工程研究所2) 武汉 430074)摘 要讨论了基于PIC MCU软件实现通用异步串口通讯的方法和与其他方法的比较。
关键词:PIC MCU 异步 软串口中图分类号:TP31Implementation of UART based on Pic MicrocontrollerCheng Pin1) G ao Wei2)(S outh-Central University for Nationalities1),Wuhan Digital Engineering Institute2),Wuhan 430074)Abstract:This paper discusses the implementation method of universal asynchronous serial(UART)communication based on PIC MCU,and takes a com parison with others.K ey w ords:PIC,MCU,asynchronous,UARTClass number:TP311 引言在没有嵌入式操作系统的情况下如何提高MCU的利用率而减少误差,一直是面向专门应用的单片机开发要解决的问题。
特别是在I/O方面,具有资源有限,实时性强等特点,决定了MCU 与外部设备通讯时要特别强调时间正确性和逻辑正确性。
串口通信在近距离传输少量数据方面具有非常便宜和易实现等特点,很多设备都提供支持RS232标准的USAR T接口,比如:GPS接收器, GSM/GPRS模块。
然而,在多数实际应用中MCU 的USAR T接口多数情况下只有一个,实际应用中一般不够用,这就要求使用软件模拟的方式来达到扩展多个UAR T的目的,同时也要满足时间正确性和逻辑正确性两大原则。
笔者在开发过程中实现了利用中断方式的软串口(UAR T)。
宝箱》。
网址: 《匠人手记》之二十四用单片机IO口实现单线单工通讯 作者:程序匠人 出处:《匠人的百宝箱》1.前言许多便宜的单片机都没有标准的串行通讯口。
因此,我们常用单片机的IO口来模拟串行通讯。
下面,匠人给出一个简单的通讯方案。
在这个方案中,从机平时处于睡眠状态。
主机处于工作状态。
在需要的时候,由主机通过通讯口唤醒从机。
从机被唤醒后接受通讯数据并进行解读,执行相关功能。
然后再次进入睡眠,等待下次唤醒。
2.硬件连接示意图3.单线单工通讯协议通讯线平时空闲时处于低电平,由一个100ms的高电平作为引导码来唤醒从机。
然后发送一个字节串行数据。
完毕后通讯线恢复到空闲状态的低电平。
对于从机来说,接受完8位数据,或检测到一个连续5t的低电平(结束码)即可认为通讯结束。
宝箱》。
网址:4.关于波特率自适应的处理在本例中,从机的振荡源是RC。
因此存在一个频率误差的问题,当系统频率变化时,可能无法正确实别“t”值。
为了能够消除该误差,可以考虑采用波特率自适应技术。
实现方法:在引导码之后,数据码之前,增加一位波特率校准位。
该校准位由一个低电平和高电平构成,低电平和高电平分别=1t。
在从机被唤醒后,检测到引导码结束后,先对校准位进行时间测量。
为后续数据码的识别提供标准时间(“t”值)。
修改后的波形图如下:5.从机通讯接收程序流程图说明:z从机在被高电平唤醒后,调用接收程序。
z通讯接收程序包括以下几个部分:1、等待引导码结束2、检测校准位,求t值3、检测数据位4、检测结束码,退出z当发生以下情况时,判为通讯失败:1、除引导码之外的任何一个低电平或高电平计时超时;2、数据位的高电平计时值≠1t,也≠3t;3、8位数据位接收完毕后,再次检测到高电平。
z通讯完毕后,接收到的数据被存储在接收寄存器中,供上级程序使用。
当通讯失败时,接收寄存器=0:z关于实时性的问题:在本例中,从机的功能比较单一。
所以,没有考虑实时性的问题。
当通讯失败时,必须等通讯线释放后才会退出接收程序。
单片机io通信(最新版)目录1.单片机 IO 通信简介2.单片机 IO 通信的基本原理3.单片机 IO 通信的常用方式4.单片机 IO 通信的实际应用5.单片机 IO 通信的未来发展趋势正文【单片机 IO 通信简介】单片机 IO 通信是指单片机与其它设备或者单片机之间的数据传输过程。
IO 通信是单片机系统设计中的重要组成部分,它直接影响到整个系统的性能和稳定性。
在实际应用中,单片机 IO 通信主要用于传感器数据采集、设备控制、数据传输等方面。
【单片机 IO 通信的基本原理】单片机 IO 通信的基本原理是通过 IO 口进行数据输入输出。
IO 口是单片机与外部设备之间的物理接口,可以通过配置 IO 口的工作模式,实现数据的输入输出。
常见的 IO 口工作模式有输入模式、输出模式、复用模式等。
【单片机 IO 通信的常用方式】单片机 IO 通信的常用方式主要有串行通信和并行通信两种。
1.串行通信:串行通信是指数据位按顺序进行传输。
在串行通信中,数据是逐个传输的,因此,传输速度较慢,但是,占用的 IO 口资源较少。
2.并行通信:并行通信是指数据位同时进行传输。
在并行通信中,数据是同时传输的,因此,传输速度较快,但是,占用的 IO 口资源较多。
【单片机 IO 通信的实际应用】单片机 IO 通信在实际应用中主要用于设备控制、数据采集、数据传输等方面。
例如,在智能家居系统中,单片机通过 IO 通信实现对家电设备的控制,实现远程控制和自动化控制。
在工业自动化系统中,单片机通过 IO 通信实现对传感器的数据采集,实现实时监控和数据分析。
在低端单⽚机之间的单线IO通信利⽤IO模拟串⼝对于接收⽐较复杂,稳定性肯定没有串⼝模块稳定性好,⽽且要占⽤⼀个定时器中断,对于不允许使⽤中断的场合就不能适应,⽐如⾼速的⽆刷控制器,我发明了⼀种⽅案可以解决这个问题,除了传输速度慢以外,有很多优点,因为越慢越稳定,⽬前为单主多从,其很容易扩展为类似can那样的单线多主⽅式,由于个⼈原因没有条件与时间将此⽅案改的完美,现在将其分享给需要的⼈/******************************************************************************************************************************************************************************************************************** File : ucos.h* By : Minglie* Date :**********************************************************************************************************/#ifndef __Ucos_H#define __Ucos_H#include "HT66F018.h"//announce all the head files#include "Main_Constant.h"void os_init();void task0(void);#define OSTCBCur 0#define OSTimeDly(k) {task[OSTCBCur].one.rdy =0; task[OSTCBCur].delay =k-1; }#define OSTimeTick()\{\#define config_max_tasks 1 //最⼤任务个数#define configTICK_RATE_us 800 //800us 配置⼼跳周期#define config_single_wire_task0_mode 0 //单线⼯作模式,0为主机,1为从机#define config_com_task0_lengh 8 //配置通信有效位数,只能取2,4,6,8//引脚配置#define COM _pc0#define COM_C _pcc0//ming_single_wire⽤到的变量#pragma rambank0OS_EXT OSTCB_TypeDef task[config_max_tasks];//task0的变量OS_EXT unsigned char task0_dat_cur;OS_EXT unsigned char task0_wait_com_h_count;OS_EXT unsigned char task0_wait_com_l_count;OS_EXT unsigned char task0_tx_buf;OS_EXT unsigned char task0_tx_buf_temp;OS_EXT unsigned char task0_rx_buf;OS_EXT unsigned char task0_rx_buf_temp;OS_EXT unsigned char task0_level_count;OS_EXT bit task0_bit_no_back;OS_EXT bit task0_bit_level_s;OS_EXT bit task0_bit_com_err;#pragma norambank#endif/********************************************************************************************************** ********************************************************************************************************* * File : ucos.c* By : Minglie* Date :********************************************************************************************************* */#include "Main_Constant.h"#include "ucos.h"void os_init(){//初始化时钟800us/////////////////////////////////////////////////////////////////_tm2c0 = 0b01010000;_tm2c1 = 0b11000001;_tm2dl = 0x00;_tm2dh = 0x00;_tm2al = configTICK_RATE_us & 0xff;_tm2ah = configTICK_RATE_us >> 8;_tm2rp = 0x00;_t2on = 1;task0_bit_level_s = 0;task0_dat_cur = 0;task0_bit_no_back = 0;task[0].step = 0;task0_bit_com_err = 0;task[0].one.rdy = 1; //任务就绪task[0].one.enable = 1; //任务使能task[0].delay = 0;task0_rx_buf = 0;task0_tx_buf = 0;}#if config_single_wire_task0_mode==0void task0(){if (task[OSTCBCur].one.rdy){switch (task[OSTCBCur].step){case0: {//初始化发送,并发送起始位1msCOM_C = 0;COM = 0;task0_tx_buf_temp = task0_tx_buf;task0_dat_cur = 0;OSTimeDly(5);COM_C = 1;OSTimeDly(5);task[OSTCBCur].step = 2;break;}case2: {//发送第0,2,4,6,8(从左数)COM_C = 0;COM = 0;if (task0_tx_buf_temp & 0b10000000){OSTimeDly(10);}else{OSTimeDly(5);}task0_tx_buf_temp <<= 1;task0_dat_cur++;task[OSTCBCur].step = 3;break;}case3: {//发送第1,3,5,7,9(从左数)COM_C = 1;if (task0_tx_buf_temp & 0b10000000){OSTimeDly(10);}else{OSTimeDly(5);}task0_tx_buf_temp <<= 1;task0_dat_cur++;if (task0_dat_cur>config_com_task0_lengh + 1) //task0_dat_cur==10, bit[0:9]发送完{task0_level_count = 0;task0_dat_cur = 0;task[OSTCBCur].step = 4;}else{task[OSTCBCur].step = 2;}break;}case4: { ////////////////////////////////////////开始接收COM_C = 1;if (COM)//等待对⽅发送,对齐{task[OSTCBCur].step = 4;task0_level_count++; //if (task0_level_count>20) //4ms{task0_level_count = 0;task0_wait_com_h_count = 0;task0_wait_com_l_count = 0;task[OSTCBCur].step = 255; //溢出,跳到异常分⽀}}else{task0_bit_level_s = 0;task0_rx_buf_temp = 0;task0_dat_cur = 0;task0_level_count = 0;task[OSTCBCur].step = 5;}break;}case5: { //////////////////////////////////////COM_C = 1;if (task0_bit_level_s == COM){task0_level_count++;if (task0_level_count>20) //4ms溢出{task0_level_count = 0;task0_wait_com_h_count = 0;task0_wait_com_l_count = 0;{if (task0_dat_cur>0) task0_rx_buf_temp <<= 1; //如果已经收到⼀些数据,将得到的数据向左移动task[OSTCBCur].step = 6;}break;}case6: { //////////////////////////////////////if (task0_level_count >= 7) task0_rx_buf_temp++; //超过1.4ms认为是1task0_bit_level_s ^= 1;task0_dat_cur++;if (task0_dat_cur >= config_com_task0_lengh) //task0_dat_cur==8说明[0:7]数据已经接收完毕{task0_level_count = 0;task[OSTCBCur].step = 7;task0_rx_buf = task0_rx_buf_temp;}else{task0_level_count = 0;task[OSTCBCur].step = 5; //接收下⼀位数据}break;}case7: { //////////////////////////////////////COM_C = 1;if (COM == 0) //等待bit[8]{task0_level_count++;if (task0_level_count>20) //4ms{task0_level_count = 0;task0_wait_com_h_count = 0;task0_wait_com_l_count = 0;task[OSTCBCur].step = 255; //溢出,跳到异常分⽀}}else{COM_C = 1;OSTimeDly(25); //延时5ms,准备下⼀次通信task[OSTCBCur].step = 0;task0_bit_no_back = 0;}break;}case255: { ////////////////////////////////////////异常分⽀COM_C = 1;task0_bit_no_back = 1;//主板不回复if (COM == 1){task0_wait_com_l_count = 0;task0_wait_com_h_count++;task[OSTCBCur].step = 255;if (task0_wait_com_h_count>20) //持续⾼4ms,重新发送{task[OSTCBCur].step = 0;task0_wait_com_h_count = 0;}}else{ //总线被拉低task0_wait_com_h_count = 0;task0_wait_com_l_count++;if (task0_wait_com_l_count>80)//16ms{task0_bit_com_err = 1; //总线被拉低task0_wait_com_l_count = 0;}}break;}}}}#elsevoid task0(){case0: {////初始化分⽀COM_C = 1;task0_level_count = 0;task0_wait_com_l_count = 0;task0_wait_com_h_count = 0;task[OSTCBCur].step = 1;break;}case1: { //等待起始位COM_C = 1;if (COM == 1){task[OSTCBCur].step = 1;task0_wait_com_h_count++;if (task0_wait_com_h_count>100)//持续拉⾼200us*100=20ms{task[OSTCBCur].step = 0; //重新开始接收}if (task0_wait_com_l_count >= 2)//检测到⼤于400us以上低电平{task0_level_count = 0;task[OSTCBCur].step = 2;}}else{task0_wait_com_l_count++;task[OSTCBCur].step = 1;}break;}case2: {//开始接收COM_C = 1;if (COM)//等待对⽅发送,对齐{task[OSTCBCur].step = 2;task0_level_count++; //if (task0_level_count>20) //4ms{task0_level_count = 0;task0_wait_com_h_count = 0;task0_wait_com_l_count = 0;task[OSTCBCur].step = 255; //溢出,跳到异常分⽀}}else{task0_level_count = 0;task0_bit_level_s = 0;task0_rx_buf_temp = 0;task0_dat_cur = 0;task[OSTCBCur].step = 3;}break;}case3: {if (task0_bit_level_s == COM){task0_level_count++;if (task0_level_count>20) //4ms溢出{task0_level_count = 0;task0_wait_com_h_count = 0;task0_wait_com_l_count = 0;task[OSTCBCur].step = 255; //溢出,跳到异常分⽀}}else{ //task0_dat_cur>0 ,说明已经得到⾄少1bit数据if (task0_dat_cur>0) task0_rx_buf_temp <<= 1; //将得到的数据向左移动task[OSTCBCur].step = 4;}break;}case4: {if (task0_level_count >= 7) task0_rx_buf_temp++; //超过1.4ms认为是1 task0_bit_level_s ^= 1;task[OSTCBCur].step = 5;task0_rx_buf = task0_rx_buf_temp;}else{task0_level_count = 0;task[OSTCBCur].step = 3; //接收下⼀位数据}break;}case5: {COM_C = 1;if (COM == 0) //等待bit[8]{task0_level_count++;if (task0_level_count>20) //4ms{task0_level_count = 0;task0_wait_com_h_count = 0;task0_wait_com_l_count = 0;task[OSTCBCur].step = 255; //溢出,跳到异常分⽀}}else{COM_C = 1;OSTimeDly(10); //延时2ms,准备发送//初始化发送task0_tx_buf_temp = task0_tx_buf;task0_dat_cur = 0;task[OSTCBCur].step = 6;}break;}case6: {//发送第0,2,4,6,8(从左数)COM_C = 0;COM = 0;if (task0_tx_buf_temp & 0b10000000){OSTimeDly(10);}else{OSTimeDly(5);}task0_tx_buf_temp <<= 1;task0_dat_cur++;task[OSTCBCur].step = 7;break;}case7: {//发送第1,3,5,7,9(从左数)COM_C = 1;if (task0_tx_buf_temp & 0b10000000){OSTimeDly(10);}else{OSTimeDly(5);}task0_tx_buf_temp <<= 1;task0_dat_cur++;if (task0_dat_cur>config_com_task0_lengh + 1) //task0_dat_cur==10, bit[0:9]发送完{task0_level_count = 0;task0_dat_cur = 0;COM_C = 1;OSTimeDly(5);//延时1ms,准备下⼀次接收task[OSTCBCur].step = 0;}else{task[OSTCBCur].step = 6;}break;}case255: { //异常分⽀COM_C = 1;task0_wait_com_h_count++;task[OSTCBCur].step = 255;if (task0_wait_com_h_count>20) //持续⾼4ms,重新接收{task[OSTCBCur].step = 0;task0_wait_com_h_count = 0;}}else{task0_wait_com_h_count = 0;task0_wait_com_l_count++;if (task0_wait_com_l_count>80)//16ms{task0_bit_com_err = 1; //总线被拉低task0_wait_com_l_count = 0;}}break;}}}}#endif对于使⽤只需引⼊这两个⽂件周期性的调⽤宏 OSTimeTick()即可实现双向通信,主机从机是⼀样的代码通过宏config_single_wire_task0_mode 加以区别,这种⽅式对于时间并不需要很精准,⽐如你1ms调⽤⼀次,突然800us调⼀次,或1200us⼀次调⽤⼀次,并不会影响通信的正确率,但是你连续的⼤偏差肯定会出问题,只需保证调⽤周期偏差可以在20%以内即可,对于将其改进为多主异步就不需要周期调⽤了。
PIC单片机I/O口单线通讯的实现
中、低档PIC单片机有些不带串口,有些虽然有串行口,却受串口固定协议的限制或留作他用,故需用普通I/O口进行通讯。
由于中、低档机I/O口数量相对较少,为节省口线,就要用I/O口模拟串行通讯。
本文以两片采用不同主频的PIC单片机(A机时钟频率为6MHz,使用口线RB6;B机时钟频率为4MHz,使用口线RB4)之间用异步通讯方式传送一组数据为例,说明I/O口一线通讯的实现方法。
一、设计思想
1.时钟同步问题
因两个单片机的时钟不同,故采用异步通讯方式。
发送、接收一位数据时,采用软件延时,保证发送、接收完全同步。
2.数据发送、接收方式
I/O口一线串行通讯,并-串(或串-并)转换用软件完成。
将欲发送的字节存于16H中,经移位指令移至进位位。
根据进位位的值,将口线RB6置0或1。
接收端RB4接收并判断后,置进位标志为0或1,再经移位指令移入14H中。
这样循环执行8次,就可将一个字节由低位到高位一位位地发送出去。
数据传送速率可用延时循环的方法进行调节。
3.握手协议
先发握手信号,后发数据。
假定A机为发送,B机为接收。
A机开始发送时,先发送一个握手数据信号,B机收到后回送一个应答信号,表示同意接收。
A机收到应答信号后,开始发送数据。
握手信号和数据信号都按异步通讯格式,先发准备信号“1”,接着发送起始位“0”,然后发数据位。
4.数据传送
异步通讯时,发送时钟控制数据位的定时移位串行输出,接收时钟检测起始位,并控制数据的定时接收移入。
两个时钟信号不是通过信号线传递,而是采用编程约定的办法,使之和实际使用的数据速率基本保持一致,而数据信号中的起始位则是发和收的同步控制。
接收时钟为数据传送波特率的16倍频信号,即一个数据位宽的时间内将会出现16个接收时钟的信号,这是检测起始位和保证在数据位中央位置接收数据所需要的。
为排除瞬时干扰,在检测到数据输入线的电平由“1”变为“0”之后,接收端将继续检测。
仅当连续8个接收时钟周期内都检测到数据线上的电平为“0”时,才确认是起始位,且发送端每一个“0”或“1”都发送16次,接收端将以16倍的时钟周期,即以位宽时间为间隔,接收各数据位(在其中央位置接收数据)。
一个字长数据(8位)接收完后,子程序返回。
二、程序框图和源程序
下面给出发送、接收一字长(8位)信号的子程序框图(见图1、图2)和PIC单片机源程序(发送、接收联络信号与数据信号相同)。
注:所有延时程序略。
1.发送子程序
listp=16c65,f=inhx8m
portbequ6
trisbequ16h
statusequ3
rp0equ5
org0x100
fsbsfstatus,rp0;选存储体1
bcftrisb,6;置RB6为输出
bcfstatus,rp0;恢复存储体0
bsfportb,6;发准备信号“1”
movlw0x08
movwf1f;置发送字长
callystb;延时同步
movlw0x10
movwf1c
fs1bcfportb,6;发16个起始位
decfsz1c,1
gotofs1
tscallystj;延时调节波特率
rrf16h,1;发送字节移位
btfscstatus,0
gototy
movlw0x10
movwf1c
fs2bcfportb,6;位为0,发16个“0”
decfsz1c,1
gotofs2
gototr
tymovlw0x10
movwf1c
fs3bsfportb,6;位为1,发16个“1”
decfsz1c,1
gotofs3
trdecfsz1f,1
gotots;发送未完,延时发下一位
return;发送结束返回
end
2.接收子程序
listp=16c65,f=inhx8m
portbequ6
trisbequ16h
statusequ3
rp0equ5
org0x200
jsbsfstatus,rp0;选存储体1
bsftrisb,4;置RB4为输入
bcfstatus,rp0;恢复存储体0
js1btfssportb,4;检测收到“1”否
gotojs1;未收到“1”继续检测
movlw0x08;置接收字长8位
movwf1f
loop1movlw0x08;置循环次数8
movwf1d
loopbtfscportb,4;检测起始位
gotoloop1;未收到“0”重置8次循环
decfsz1d,1
gotoloop;收到“0”继续检测
jzcallystb;收到8个“0”,延时同步,接收数据
btfscportb,4;测试接收位
gotojy
bcfstatus,0;收到“0”置c=0
gotoj1
jybsfstatus,0;收到“1”置c=1
j1rrf14h,1;接收位移入14hdecfsz1f,1
gotojz;未接收完,延时接收下一位return;接收完返回
end
PIC单片机 。