新学期伊始,不忘助力国产替代初心,手头没有试验箱,先用“擎天柱”带领大一同学,跟随冲哥视频,学用STC AI8051U芯片讲义。 第七节 学用PWM驱动擎天柱LED本节课主要任务是学习PWM相关寄存器及配置产生PWM方波,动态改变方波占空比,驱动擎天柱P2端口LED,展示呼吸效果。一、学习了解PWM相关寄存器芯片手册第二十九章介绍PWM,STC AI8051U内部集成了8通道16位高级PWM定时器,分PWMA和PWMB两组,其中PWMA可配置4组互补/对称STC AI8051U芯片/死区控制的PWM或者捕捉外部信号。PWMB与PWMA唯一区别是PWMA可带死区的互补对称PWM,其他功能一样,所以我们只学习好PWMA即可。PWMA时钟频率可以用系统时钟或外部计时,PWMA时基单元包含,16位计数器、16位自动重载寄存器、重复计数器、预分频器。
其时钟频率是经过设置PWMA_PSCRH和PWMA_PSCRL,进行分频(值1-65535);配置输入输出的引脚寄存器PWMA_ENO;配置PWMA_CCMR1、PWMA_CCER1、PWMA_BKR,打开PWMA_CR1计数,产生PWM信号输出。二、配置PWM相关寄存器1.时钟源选择, 这里选用系统时钟,默认40Mhz2.时基单元选择PWMA_PSCR
//设置周期时间PWMA_ARR
//设置捕获比较寄存器PWMA_CCR//设置占空比时间
3.输入输出的引脚配置//使能PWM1n通道输出PWMA_ENO
//选择PWM从P2引脚输出PWMA_PS擎天柱LED灯接P2端口,所以要配置PWM从P2端口输出
4.输入输出模式设置//配置通道输出使能和极性PWMA_CCER
//通道PWM模式配置PWMA_CCMR
//使能主输出PWMA_BKR = 0X80;
//使能ARR预装载,启动计数器PWMA_CR1
三、定义相关变量和任务函数1. 定义9个变量,4个变量记录占空比,4个记录状态翻转LED灯亮度,1个编辑记录周期。占空比:PWM1_Duty、PWM2_Duty、PWM3_Duty、PWM4_Duty翻转状态:PWM1_Flag、 PWM2_Flag、 PWM3_Flag、PWM4_Flag计数周期:PWM_PERIOD2. 定义一个动态改变占空比函数。void ChangePWM (void){if(!PWM1_Flag) { PWM1_Duty++; if(PWM1_Duty > PWM_PERIOD) PWM1_Flag = 1; } else { PWM1_Duty--; if(PWM1_Duty <= 0) PWM1_Flag = 0; } if(!PWM2_Flag) { PWM2_Duty++; if(PWM2_Duty > PWM_PERIOD) PWM2_Flag = 1; } else { PWM2_Duty--; if(PWM2_Duty <= 0) PWM2_Flag = 0; } if(!PWM3_Flag) { PWM3_Duty++; if(PWM3_Duty > PWM_PERIOD) PWM3_Flag = 1; } else { PWM3_Duty--; if(PWM3_Duty <= 0) PWM3_Flag = 0; } if(!PWM4_Flag) { PWM4_Duty++; if(PWM4_Duty > PWM_PERIOD) PWM4_Flag = 1; } else { PWM4_Duty--; if(PWM4_Duty <= 0) PWM4_Flag = 0; } PWMA_CCR1H = (u8)(PWM1_Duty >> 8); //设置占空比时间 PWMA_CCR1L = (u8)(PWM1_Duty); PWMA_CCR2H = (u8)(PWM2_Duty >> 8); //设置占空比时间 PWMA_CCR2L = (u8)(PWM2_Duty); PWMA_CCR3H = (u8)(PWM3_Duty >> 8); //设置占空比时间 PWMA_CCR3L = (u8)(PWM3_Duty); PWMA_CCR4H = (u8)(PWM4_Duty >> 8); //设置占空比时间 PWMA_CCR4L = (u8)(PWM4_Duty);}3. 编译烧录拷贝上一节课代码,在task.c文件任务计划函数添加一行:{0,5,5,ChangePWM},为了避免LED亮灯冲突,要注释掉test_Demo中P2=t_display这一行代码。新建一个pwm.c文件和pwm.h文件,并添加到项目中,创建PWM_config初始化函数和ChangePWM任务回调函数。编译烧录,在欣赏过程中,建议捋清楚pwm配置过程,最好按手册中流程图记忆,这样方便日后配置。
新学期伊始,不忘助力国产替代初心,AI8051U试验箱刚收到,结合“擎天柱”带领大一同学,跟随冲哥视频,学用STC AI8051U芯片讲义。 第八节、学用实验箱内芯片74HC595本节课主要任务是学习芯片74HC595,点亮实验箱数码管。一、学习了解移位寄存器74HC5951.芯片概述:74HC595是一款8位CMOS移位寄存器。8位并行输出端口为可控的三态输出,一个串行输出端口,可以实现多级芯片串行控制,组成 8n 位(n 为芯片数量)并行输出。2.芯片管脚定义:管脚1-7和15共8引脚为QA~QH八位数据并行输出端;第八脚GND电源地;第九脚Q′H是串行数据输出管脚;第十脚RESET移位寄存器清零端;第十一脚SCK数据输入时钟端;第十二脚RCK输出存储器锁存时钟端;第十三脚EN输出使能端;第十四脚DATA数据输入端;第十六脚VCC电源端。3.芯片真值表
输入管脚输出管脚
1412111013
SERRCKSCKRESET EN
XXXXHQA~QH 输出端高阻态
XXXXLQA~QH 输出端输出有效值 L 或 H
XXXLL移位寄存器清零, Q'H=0
LX↑HL移位寄存器存储 L 值, Q'H输出 Qn-1
HX↑HL移位寄存器存储 H 值, Q'H输出 Qn-1
XX↓HL移位寄存器状态保持不变
X↑XHL8 位锁存移位寄存器中的状态值并行输出
X↓XHL存储器输出状态保持不变
二、实验箱数码管接法1. 数码管电气连接:实验箱使用两块74HC595芯片,A块74HC595芯片输出接数码管位码,B块74HC595芯片输出接数码管段码(每个数码管abcdefgh合称段码),数据是从A级联到B;所以数据是要先传数码管段码再传位码。
三、实验箱代码学习void Send_595(u8 dat) //向74HC595芯片发送数据函数{ u8i; for(i=0; i<8; i++) { dat <<= 1; P_HC595_SER = CY;//P_HC595_SER = P3^4;芯片第14引脚 P_HC595_SRCLK = 1;//P_HC595_SRCLK = P3^2; 芯片第11引脚 P_HC595_SRCLK = 0; }}dat <<= 1 左移1位后,被移出去数存在CY寄存器中,P_HC595_SER = CY即数据从14脚输入,根据上面的真值表,可以知道,芯片第11引脚SCK电平上升沿即移位寄存器存储输入数据,超出8位数据从芯片第九引脚输出,级联到下一块74HC595芯片。void DisplayScan(void)//从74HC595芯片读取数据函数{ Send_595(t_display]); //输出段码 Send_595(~T_COM); //输出位码 P_HC595_RCLK = 1;//P_HC595_RCLK= P3^5;芯片第12引脚 P_HC595_RCLK = 0; if(++display_index >= 8) display_index = 0; //8位结束回0}实验箱的74HC595芯片A、B第12引脚接在一起,由P3^5统一控制,根据上面的真值表,可以知道,单片机P3^5引脚输出高电平,74HC595芯片A、B输出数码管段码和位码。
新学期伊始,不忘助力国产替代初心,AI8051U试验箱刚收到,结合“擎天柱”带领大一同学,跟随冲哥视频,学用STC AI8051U芯片讲义。
第九节、学用实验箱NTC测温本节课主要任务是学习NTC测温原理和实验箱17-ADC采集NTC热敏电阻测温度代码。一、学习了解NTC温度传感器 NTC温度传感器是一种热敏电阻、探头,通常由2或3种金属氧化物组成, 混合在类似流体的黏土中,并在高温炉内锻烧成致密的烧结陶瓷。其测温原理为:利用NTC热敏电阻在一定的测量功率下,电阻值随着温度而变化且值是一一对应,利用这一特性, 可将NTC热敏电阻通过测量其电阻值来确定相应的温度,从而达到检测和控制温度的目的。二、实验箱NTC电气连接 实验箱由单片机P51端口给NTC测温电路供电,NTC探头与10K电阻串联,两者的节点连到接线柱,由跳线选择与示波器探头连接ADC3,NTC探头一端接地,如下图所示。NTC测温实际上检测NTC与10K电阻分压,对应单片机12位ADC精度值4096的比值。
三、单片机有关ADC寄存器单片机ADC相关寄存器有时序控制寄存器、转换结果寄存器、ADC配置寄存器、ADC控制寄存器1.ADCTIM //时序控制寄存器 B7 :CSSETUP //通道选择时间 B6-B5:CSHOLD//通道保持时间 B4-B0:SMPDUTY //信号采样速度,不能小于11个ADC时钟。 2.ADC转换结果寄存器 ADC_RES//高字节 ADC_RESL //低字节3.ADCCFG //ADC配置寄存器 B5: RESFMT //ADC转换结果格式控制,0左对齐、1右对齐 B3-B0: SPEED//ADC工作时钟频率 4.ADC_CONTR//ADC控制寄存器 B7 :ADC_POWER //ADC电源控制,延长1毫秒让ADC供电稳定 B6 :ADC_START //ADC转换启动控制 B5 :ADC_FLAG //ADC转换结束标志,需要软件清除。 B4 :ADC_EPWMT //使能PWM实时触发ADC功能 B3-B0:ADC_CHS //ADC模拟通道选择 配置流程,先设置时序控制,通道选择和保持时间维持默认值,但信号采样速度,不能小于11个ADC时钟(设置时要大于01010B),建议设置最慢32个时钟(11111B);再配置ADC转换结果格式,常用的是右对齐,转换时间建议设置最慢(1111B)为系统时钟/2/16;接着选择芯片io的ADC采样引脚,并且将io设置高阻模式(昨天我移植学习代码时,就是遗漏了io引脚高阻模式设置,让走了弯路);最后开启ADC电源并延长1毫秒让ADC供电稳定使能ADC。四、源代码学习解析 本章节NTC测温涉及ADC_Config初始化函数,get_temperature计算温度函数和Get_ADC12bitResult采集NTC的ADC值函数,还有一张电阻值与温度对应表u16 code temp_table[];下面对函数关键语句进行解析。void ADC_Config(void) //ADC初始化函数{ ADCTIM = 0x3f;//设置 ADC 内部时序,ADC采样时间建议设最大值 ADCCFG = 0x2f;//设置 ADC 时钟为系统时钟/2/16/16 ADC_CONTR = 0x80;//使能 ADC 模块}//ADC采集函数u16 Get_ADC12bitResult(u8 channel)//channel为ADC采集通道,值为0到15{ ADC_RES = 0; //清零存储ADC转换值高字节 ADC_RESL = 0; //清零存储ADC转换值低字节 ADC_CONTR = (ADC_CONTR & 0xf0) | channel; //设置ADC转换通道 ADC_START = 1; //启动ADC转换 _nop_();//延时 _nop_(); _nop_(); _nop_();
while(ADC_FLAG == 0); //等待转换,ADC转换结束自动将ADC_FLAG标志置1 ADC_FLAG = 0; //软件清除ADC结束标志 return(((u16)ADC_RES << 8) | ADC_RESL);//返回转换结果,值是16位数}//计算温度函数u16 get_temperature(void){ u16 code *p; //引用电阻值与温度对应表指针 u16 i,adc; u8j,k,min,max; adc = Get_ADC12bitResult(3);//实验箱ADC3采集,故参数为3 if(adc < 4096) { adc = 4096 - adc; //由于大咖Coody将NTC温度与阻值对应的ADC值颠倒放置,相当于将NTC电气连接方式倒置,采集的是10k固定电阻分压情况,所以要将4096减去。 p = temp_table; //引用NTC温度与阻值对应表 if(adc < p) return (0xfffe);//小于表最小值,超量程 if(adc > p) return (0xffff);//大于表最大值,超量程 min = 0; //-40度时序号为0 max = 160; //120度时序号为160
for(j=0; j<5; j++)//二分折半查询法,缩小范围 { k = min / 2 + max / 2; if(adc <= p) max = k; else min = k; } if(adc == p)i = min * D_SCALE;// else if(adc == p)i = max * D_SCALE; else // adc值为表范围区间值,min < temp < max { while(min <= max)//区间范围上下限不相当时 { min++;//下限逐步累计逼近上限值,比如p累加成p if(adc == p) {i = min * D_SCALE; break;} else if(adc < p)//adc值在表中相邻两档值之间时,即比如表下限p=2048,p=2093,adc=2070情况,下面以此情况解析。 { min--;//下限退回,即p变成p i = p; //i记录p值,2048/*j记录adc值比p多部分,占p与p之间比值。(adc - i) * D_SCALE:(2070-2048)×10=220;(p - i):2093-2048=45J=220÷45=4.89≈5*/ j = (adc - i) * D_SCALE / (p - i); i = min;//i=65 i *= D_SCALE; //i=650 i += j; //i=650+4.89=654.89≈655 break; } } } }return i;}
新学期伊始,不忘助力国产替代初心,带领大一同学,借用AI8051U试验箱和“擎天柱”,跟随冲哥视频,学用STC AI8051U芯片讲义。 第十节、学用AI8051U串口本节课主要任务是学习AI8051U试验箱代码包“18-P1.3做ADC3-使用ADC15测量内部1.19V信号源,计算外部电压”源代码,学会配置串口寄存器。一、学习了解AI8051U串口概况AI8051U系列单片机具有4个串口通信接口(USART1、USART2、USART3和USART4),其中USART1和USART2是全双工同步/异步串口通信接口,USART3和USART4是全双工异步串口通信接口。每个串行口由2个数据缓冲器、一个移位寄存器、一个串行控制寄存器、一个波特率发生器等组成。每个串行口的数据缓冲器由2个互相独立的接收、发送缓冲器构成,可以同时发送和接收数据。USART1和USART2均有4种工作方式,其中两种方式的波特率是可变的,另两种波特率是固定的。USART3和USART4都有两种工作方式,波特率都是可变的。四个串口通讯口通过功能管脚切换到多组端口,可以实现一个通讯口分时复用为多个通讯口。二、串口寄存器配置步骤1. 功能脚切换。2. 串口工作模式配置。3. 串口波特率发生器选择4. 定时器时钟模式选择5. 定时器计数器寄存器重载6. 定时器控制寄存器使能7. 串口数据寄存器处置8. 串口中断请求标志处置三、学习了解串口寄存器1、串口功能脚切换。P_SW1、P_SW2
2、串口工作模式配置通常配置为可变波特率8位数据方式,即SCON寄存器B7位设置为0,B6位设置为1;实现代码如下:SCON = (SCON & 0x3f) | 0x40;
3、串口波特率发生器选择和定时器时钟模式选择AUXR寄存器B0位值确定波特率发生器,B2、B6、B7定时器速度控制位,如下图。
4、定时器计数寄存器
5、定时器控制寄存器启动
6、串口数据寄存器SBUF、S2BUF
7、串口中断请求标志
上面的寄存器设置,看着很复杂,但作为初学者,建议有必要学习一下,将来实际开发应用时,可直接使用STC的Aicube工具可视化设置,简单、快速、准确。
新学期伊始,不忘助力国产替代初心,带领大一同学,借用AI8051U试验箱和“擎天柱”,跟随冲哥视频,学用STC AI8051U芯片讲义。 第十一节、学用操作AI8051U内部EEPROM本节课主要任务是学习AI8051U试验箱代码包“19-通过串口发送命令读写EEPROM测试程序”源代码,学习了解AI8051U内部EEPROM。一、学习了解AI8051U内部EEPROM概况Ai8051U系列单片机内部集成了大容量的EEPROM,EEPROM可分为若干扇区,每个扇区512字节,访问EEPROM有IAP和MOV两种方式。IAP方式可以对EEPROM执行读、写、擦出操作,MOV只能对EEPROM进行读操作,不能进行写和擦除操作。EEPROM的写操作智能将字节中的1写0,要将字节中0写为1必须执行扇区擦除操作;EEPROM的读写操作是以1字节为单位进行,每执行一次读或写命令,只能读出或者写入一个字节数据;而擦除操作是以扇区为单位,每个扇区512字节。两种方式访问EEPROM前都需要设置正确的目标地址。EEPROM读、写、擦除操作所需时间不同,但都是硬件自动控制,只需要正确配置IAP_TPS寄存器即可。程序代码只有主循环中或者只有中断代码中使用IAP方式对EEPROM进行操作,则不需要关闭中断;如果主循环代码和中断代码都有使用IAP方式对EEPROM进行操作,那么操作EEPROM时必须关闭中断。二、学习掌握有关EEPROM的寄存器1. EEPROM控制寄存器:IAP_CONTRIAP_CONTR的B7 位IAPEN =1时使能EEPROM操作,B4位CMD_FAIL是失败状态位,此位需要软件清零;B6、B3位是软件复位启动选择;B5位是软件复位触发位。2. EEPROM数据寄存器:IAP_DATA。读操作时,保存读出EEPROM的数据;写操作时,保存写入的数据。3. EEPROM地址寄存器:IAP_ADDR进行读、写、擦除操作的目标地址寄存器。IAP_ADDRH保存地址的高字节,IAP_ADDRL保存地址的低字节。4. EEPROM命令寄存器:IAP_CMDIAP_CMD的B2、B1、B0三位组合确定EEPROM的操作命令。CMD=000(CMD0)为空操作;CMD=001(CMD1)为读字节命令;CMD=010(CMD2)为写字节命令;CMD=011(CMD3)为擦除扇区命令;执行CMD2写字节命令前,必须先将写的数据保存在IAP_DATA中,再发写命令。5. EEPROM触发寄存器:IAP_TRIG设置完成EEPROM读、写、擦除的命令寄存器、地址寄存器、数据寄存器和控制寄存器后,需要向IAP_TRIG先写入5AH再写入A5H命令来触发读、写、擦除操作,而且每次对EEPROM操作都要向IAP_TRIG写入触发命令。操作完成后,EEPROM地址寄存器和命令寄存器内容没变,对下一个目标进行操作时,需要手动更新这些寄存器。6. EEPROM擦除等待控制寄存器:IAP_TPSIAP_TPS=系统工作频率/1000000,小数部分四舍五入进行取整数。三、EEPROM操作数据地址规范EEPROM在64K的flash存储空间中位于FF:C000h---FF:FFFFh。EEPROM总是从后向前规划的,所以无论设置多少,EEPROM在flash存储空间中结束地址始终是FF:FFFFh。使用IAP方式访问,地址数据为EEPROM的目的地址,地址从0000开始,用MOV指令读取EEPROM数据,地址数据为:基地址FF:0000h+程序大小的偏移+EEPROM的目标地址。四、EEPROM操作实现几个函数1、EEPROM命令触发函数:void EEPROM_Trig(void){ F0 = EA; //F0是程序状态寄存器通用标志,保存全局中断 EA = 0; //禁止中断, 避免触发命令无效 IAP_TRIG = 0x5A; IAP_TRIG = 0xA5; _nop_(); //延迟时间确保IAP_DATA的数据完成准备 _nop_(); _nop_(); _nop_(); EA = F0; //恢复全局中断}2、EEPROM禁止访问函数void DisableEEPROM(void) //禁止访问EEPROM{ IAP_CONTR = 0; //关闭 IAP 功能 IAP_CMD = 0; //清除命令寄存器 IAP_TRIG = 0; //清除触发寄存器 IAP_ADDRE = 0xff; //将地址设置到非 IAP 区域 IAP_ADDRH = 0xff; //将地址设置到非 IAP 区域 IAP_ADDRL = 0xff;}3、EEPROM使能函数void IAP_ENABLE(void){IAP_CONTR |= 0x80;IAP_TPS = MAIN_Fosc / 1000000;//设置等待时间,要取整数}4、EEPROM读取函数void EEPROM_read_n(u32 EE_address,u8 *DataAddress,u8 length){ IAP_ENABLE(); //使能EEPROM操作 IAP_CMD = 1; //读EEPROM命令,只需设置一次即可 do { IAP_ADDRE = (u8)(EE_address >> 16); //地址高字节 IAP_ADDRH = (u8)(EE_address >> 8);//送地址中字节 IAP_ADDRL = (u8)EE_address; //送地址低字节 EEPROM_Trig(); //触发EEPROM操作 *DataAddress = IAP_DATA; //读出的数据送往 EE_address++; DataAddress++; }while(--length); DisableEEPROM();}EE_address这里是32位数,IAP_ADDRE、IAP_ADDRH、IAP_ADDRL接力存储了1、2、3个字节,最高位第四字节数据没用,单片机是24位寻址机制。5、EEPROM写入函数void EEPROM_write_n(u32 EE_address,u8 *DataAddress,u8 length){ if(length ){ IAP_ENABLE(); //使能EEPROM操作 IAP_CMD = 2; //字节写命令 do { IAP_ADDRE = (u8)(EE_address >> 16); //地址高字节 IAP_ADDRH = (u8)(EE_address >> 8);//地址中字节 IAP_ADDRL = (u8)EE_address; //地址低字节 IAP_DATA= *DataAddress; //送数据到IAP_DATA EEPROM_Trig(); //触发EEPROM操作 EE_address++; //下一个地址 DataAddress++; //下一个数据 }while(--length); //直到结束DisableEEPROM();}}
新学期伊始,不忘助力国产替代初心,带领大一同学,借用AI8051U试验箱和“擎天柱”,跟随冲哥视频,学用STC AI8051U芯片讲义。 第十二节、学用IIC操作AI8051U实验箱内置AT24C02本节课主要任务是学习AI8051U试验箱代码包“28-I2C主机模式访问AT24C02程序”源代码,学习了解IIC总线。一、学习了解IIC总线IIC总线是飞利浦公司推出的一种用于微控制器和外围设备进行通信的串行总线,属于一主多从的总线结构,总线上的每个设备都有一个特定的设备地址,通讯只要两根线,一根数据线SDA,另一根是时钟线SCL,通信都是由主设备发起,从设备被动响应。一般具有IIC总线的元件,其SDA和SCL信号线管脚都是漏极开路输出结构,所以不同器件的SDA与SDA和SCL与SCL之间不需要额外转换电路,可以直接相连,但使用时,SDA和SCL信号线都必须加上拉电阻。二、IIC总线数据传输在IIC总线上,数据是伴随时钟脉冲,由高到低逐位传输,每位数据占用一个时钟脉冲。时钟线SCL高电平期间,SDA线电平高低状态表示传输的数据,高电平为1,低电平为0;传输数据时,SCL为低电平期间,SDA要完成高低电平转换,SCL高电平期间,SDA状态必须保持稳定,否则数据传输会失败。IIC总线数据传输时,包含起始信号、寻址信号、应答信号、传输数据和终止信号。起始信号:SCL为高电平期间,SDA由高电平变成低电平的变化。SCL和SDA高电平要维持大于4.7微秒,再改变SDA为低电平并维持大于4微秒。终止信号:SCL为高电平期间,SDA由低电平向高电平变化,SDA变化前,SCL高电平和SDA低电平维持大于4微秒,SDA由低电平变高电平维持高电平大于4.7微秒。寻址信号:IIC总线约定寻址信号包括从机地址和数据传输方向,即从机地址D7-D1,加上数据传输方向,0表示写(主机传到从机),1表示读(从机到主机);应答信号:IIC总线分应答信号ACK和非应答信号NACK,IIC总线是以字节方式传输数据,发送一个字节后,在时钟的第九个脉冲期间,释放SDA数据线,由接收方发送应答信号,即把SDA电平拉低表示数据接收成功ACK,SDA电平置高表示无应答NACK。SDA电平状态要维持大于4微秒。 三、IIC主设备与从设备通信(1)主设备给从设备发送/写入数据:1. 主设备发送起始(START)信号2. 主设备发送设备地址到从设备3. 等待从设备响应(ACK)4. 主设备发送数据到从设备,一般发送的每个字节数据后会跟着等待接收来自从设备的响应(ACK)5. 数据发送完毕,主设备发送停止(STOP)信号终止传输(2)主设备从从设备接收/读取数据1. 设备发送起始(START)信号2. 主设备发送设备地址到从设备3. 等待从设备响应(ACK)4. 主设备接收来自从设备的数据,一般接收的每个字节数据后会跟着向从设备发送一个响应(ACK)5. 一般接收到最后一个数据后会发送一个无效响应(NACK),然后主设备发送停止(STOP)信号终止传输四、实现IIC总线数据传输函数1. 延时函数:用STC下载工具生成。void Delay5us(void) //@40.000MHz{ unsigned long edata i; _nop_(); _nop_();_nop_();i = 48UL;while (i) i--;}2. IIC开始void IIC_Start(void) //IIC开始{ SCL = 1; //时钟SCL线拉高 SDA = 1; //通讯线SDA拉高 Delay5us(); //延迟确保时钟SCL线和通讯线SDA高电平超过4.7微秒 SDA = 0; //通讯线SDA拉低 Delay5us(); //延迟确保时钟SCL线高电平期间,通讯线SDA低电平超过4微秒SCL = 0; //时钟SCL线拉低Delay5us();}3. IIC结束void IIC_Stop(void)//IIC结束{SCL = 0;SDA = 0;//通讯线SDA拉低Delay5us(); //延迟SCL = 1;//时钟SCL线拉高 Delay5us(); //延迟确保时钟SCL线高电平期间,通讯线SDA低电平超过4微秒 SDA = 1;Delay5us(); //延迟确保时钟SCL线和通讯线SDA高电平超过4.7微秒;}4. IIC发送ackvoid IIC_ACK(void){SDA = 0;//通讯线SDA拉低 Delay5us();//延迟 SCL = 1;//时钟SCL线拉高 Delay5us();//延迟确保时钟SCL线高电平期间,通讯线SDA低电平超过4微秒 SCL = 0;//时钟SCL线拉低 Delay5us();//延迟}5. IIC发送NACKvoid IIC_ACK(void){SDA = 1;//通讯线SDA拉高 Delay5us();//延迟 SCL = 1;//时钟SCL线拉高 Delay5us();//延迟确保时钟SCL线高电平期间,通讯线SDA高电平超过4微秒 SCL = 0;//时钟SCL线拉低 Delay5us();//延迟}6. IIC等待从机ACKvoid IIC_WaitACK(void) //等从机回应ACK{SDA = 1;//拉高释放通讯线SDADelay5us();//延迟等待从机相应稳定电平后SCL = 1;//时钟SCL线拉高锁定读取SDA电平,判定从机是否应答Delay5us();//延迟ack = SDA;//读取ACK回应状态Delay5us();//延迟SCL = 0;//拉低时钟SCL完成读取Delay5us();//延迟}7. IIC发送一个字节void IIC_SendByte(u8 dat) //发送一个字节{u8 i;for(i=0;i<8;i++){ if( dat& 0x80 )//1000 0000与dat最高位对比,SDA = 1; else SDA = 0; Delay5us(); SCL = 1; Delay5us(); SCL = 0; Delay5us(); dat<<=1;} }8. IIC读取一个字节u8 IIC_ReadByte(void) //读取一个字节{ u8 i=8,dat=0; SDA = 1;//释放SDA通讯线,以便从机控制SDA。Delay5us(); do { SCL = 1; Delay5us() dat<<=1; if( SDA ) dat |= 1; SCL = 0; IIC_DELAY();}while(--i); return dat;}9. IIC写入连续的几个字节void IIC_Write_NByte( u8 slave,u8 addr,u8 *p,u8 number ){IIC_START();//开始命令IIC_SENDBYTE(slave);//发送从机地址IIC_WAITACK();//等待从机应答if( !ack )//从机应答ack=0{ IIC_SENDBYTE(addr);//发送数据存储地址,就是表达数据要存哪儿 IIC_WAITACK();//等候从机应答确认收到地址数据 if( !ack )//确认从机收到地址数据ack=0 { do { IIC_SENDBYTE(*p);//发送数组第一个数 p++;//数组指针累加,指向数组下一个数 IIC_WAITACK();//等候从机应答 if( ack )//从机应答失败 break;//推出循环终止写入 } while(--number);//从机正确应答继续循环写 }}IIC_STOP();//写完释放通信}10. iic读取连续的几个字节void IIC_Read_NByte( u8 slave,u8 addr,u8 *p,u8 number ) { IIC_START();//开始命令 IIC_SENDBYTE(slave);//发送从机物理电气连接地址 IIC_WAITACK();//等待从机应答 if( !ack )//确认从机应答ack=0 { IIC_SENDBYTE(addr);//发送数据地址,即从芯片内哪儿读 IIC_WAITACK();//等待从机应答 if( !ack )//确认从机应答在哪个地址读 { IIC_START();//开始命令 IIC_SENDBYTE((u8)(slave+0x01)); //指令从机输出数据 IIC_WAITACK();//等待从机应答 if( !ack )//从机应答ack=0 { do { *p = IIC_READBYTE(); //P => P p++; if( number!=1 ) IIC_SENDACK(); } while(--number); IIC_SENDNACK(); } } } IIC_STOP(); }
页:
1
[2]