今天起博客搬家了 地址是:digfarmer.org
跳到那边去吧
最近电脑有问题,一重装电脑就忘了备份这个,又得重新写了,备份一下在博客安全,那都能找到。
@echo off echo 1.自动获取IP 2.公司IP echo 3.打开WIFI 4.关闭WIFI echo 5.重设WIFI 6.网络承载信息 echo\ set/p input=请输入序号: if %input%==1 (netsh interface ip set address name="本地连接" source=dhcp netsh interface ip set dns name="本地连接" source=dhcp netsh wlan start hostednetwork) if %input%==2 (netsh interface ip set address name="本地连接" source=static addr=172.16.23.139 mask=255.255.0.0 gateway=172.16.254.11 netsh interface ip set dns name="本地连接" source=static addr=202.101.172.35 netsh interface ip add dns name="本地连接" addr=202.102.172.47 index=2 netsh wlan start hostednetwork) if %input%==3 netsh wlan start hostednetwork if %input%==4 netsh wlan stop hostednetwork if %input%==5 (netsh wlan set hostednetwork mode=allow ssid=Bruce key=ckbin0088 netsh wlan start hostednetwork) if %input%==6 netsh wlan show hostednetwork pause
自己手工焊的,实在有点不恭维,话说怎么东整西整的,多少有接触问题,再加上修改难度,决定还是画一版实验板来做实验的安全。上天保佑,就剩下闭环这一步了,保佑我这次成功把,已经折腾了好多个月了
记录一下,这事每次装每次都忘,MDK 出了最新4.6 版本,由于版本控的缘故,就装上了。倒是最后注册不了,还以为TMD 软件增强了加密注册。度娘也没找到答案,倒是早上运行bat的时候要右键“以管理员身份运行” 才记起,在WIN7 下注册MDK 必须“以管理员身份运行”才能注册,这些好了,OK了~~~
基本能搜到的systick 都是作为延时使用的,因为设计需求我更多实用的是系统时间判断。
假如我有个LED 需要每10s 闪一下,并且单片机还需要做其他的工作,用延时工作效率太低了,开个定时器又太浪费了。因此系统时钟就体现出了由为重要的应用场合。只需要检测到系统时间为10s 的倍数就可以做动作了,当然前提保证程序的大体循环能在1s 内完成,这个基本没问题如果一个大体循环1s 内完成不了 那这个程序要么就是大到无法形容,要么就是无止境的运行。
首先进入while(1) 大循环前初始化systick,进入主体程序就在计数了,计数分毫秒,秒,这样能在特点的时间进入指定的程序中运行。
初始化systick
void TimeCount_Init(void) { SysTick->LOAD=72000000/1000;//系统频率为72MH SysTick->VAL=0x00; SysTick->CTRL=0xFFFFFFFF; MilliS=0; Second=0; Min=0; }
当然如果用库函数也行的
void TimeCount_Init(void) { if (SysTick_Config (SystemCoreClock / 1000)) { while (1); } MilliS=0; Second=0; Min=0; }
中断函数
void SysTick_Handler(void) { MilliS++; if(MilliS>=10000) MilliS=0;//此处10000ms 主要方便延时函数使用 if(MilliS%1000==0) {Second++;} if(Second>=60) {Second=0;min++;} }
如果我们要想5秒去做一次计算某组数据只需要写入秒判断即可
if(Second%5 == 0)
{ 需要间隔运行的程序…… }
毫秒也是可以的,换成MilliS 即可,甚至分钟都行。
好了,那延时怎么办?是的特殊场合我们可能还是可能有需要延时函数的。当然这个也是可以做到的,不过相对运算多一点点。
延时函数如下:
u8 delayms(u16 nCount) { u16 CurTim=MilliS; u16 i=0; if(nCount<60000) { if(CurTim+nCount<10000) { while(MilliS-CurTim<nCount); return 1; } i=nCount-(10000-CurTim); while(MilliS<9998); while(MilliS>=9998||MilliS<i); return 1; } delayS(nCount/1000); delayms(nCount%1000); //while() return 1; } u8 delayS(u16 nCount) { u16 CurTim=Second; u16 i=0; if(nCount<6000) { if(CurTim+nCount<60) { while(Second-CurTim<nCount);return 1;} i=nCount-(60-CurTim); while(Second<59); while(Second>=59||Second<i); return 1; } return 0; }
这里我做的毫秒延时中实际最长的只能计算60000ms 即60s的延时 再长的延时就会先调用秒延时,运行完后再把剩下的毫秒延时运行掉。所以超出部分将计算越出计数器最大计算值多少来计算i=nCount-(10000-CurTim);而中断中定义的技术最大值10000 原因是一般我们使用延时都不会太长,最长一般也就数秒而已,更多的是毫秒级的,所以这里放宽至10S 的长度,直接等待值到了就推出,所以10S内的延时延时还是非常精确的,但如果大于就会有几个微秒的差距了,中间插入了好几条运算和指令,非精确定时就别用这个定时器了。
话说之前只是用EMACS的原配功能 C-x r * 这个功能的矩阵编辑,非实时的 输入完后再确认才会把输入的内容插入矩阵编辑中。经网友推介用cua-base 这插件。详细说的网上都是同一篇内容被转载几百次,一个叼样。说emacs 内配了又不说怎么调用。琢磨了一番加载配置应该写入
原网站还有更详细的介绍和更多的操作 http://www.cua.dk/cua.html
前面写过定时器TIME的相关原理和使用,PWM其实也是在其基础上补充出来的功能。首先看定时器的框图
这是高级定时器的框图,通用定时器少了图中DTG寄存器,此寄存器是做为死区设置的,在这里暂且不管。
单单定时器应用而已,是在自动重装载寄存器与计数器所产生的中断中所应用的,而PWM输出是在其计数器后一级加入一比较器后再做输出的。多出的一级寄存器为CCRx 捕获/比较寄存器,与计数器CNT 一样同为16位的寄存器,当CNT的值小于CCRx 中的值时候输出高电平或低电平,当大于的时候反向,当然也可以设置CCRx 的值大于ARR重载寄存器的值,这样就是一个占空比为100% 或0%的输出,失去了PWM的意义。手册上说的由ARR来确定频率,这我认为的是ARR更应该定义为确定最大周期长度,而要设定频率和占空比精度的更关联的是PSC预分频寄存器,预分频寄存器把单个计数时间分得更小,就能获得同样周期的更精细的占空比千分之一或万分之一,PWM的周期也能设定得更短。所以PWM 的频率是由PSC和ARR两个寄存器所决定的,我的建议是首先初始化就设定好一个较小的PSC 值,计数器单个计数周期可达数十微秒级别的,这样便能由重载寄存器更好的控制PWM的 脉冲周期长度,短可达微秒单位,长可达毫秒。
下图为更为直接的PWM 输出关系图
ARR寄存器设定脉冲周期,CRRx设定占空比,CNT计数器最大值为ARR载入。
每组TIM有4组独立通道,图1中有表示的,CCR1、CCR2、CCR3、CCR4,即一组TIM可以输出4组 相同频率不同占空比的脉冲输出。
PWM的控制寄存器有CCMR1、CCMR2 设定输入输出模式,CCMR1 高8位对应通道2,低8位对应通道1,CCMR2高8位对应通道4,低8位对应通道3。组要控制输出对应电平及计数方式等。
CR2使能PWM 反向控制的输出使能。
CCER 输出极性控制以及通道使能。
以上寄存器功能详细请看数据手册。
库函数分析:
3.0的固件库 与PWM输出相关的设置函数是TIM_OCxInit。在原先TIM定时器的函数设定上再加上次函数的设定即可。3.0函数与2.0函数相比没了 TIM_Channel 这个数据类,转而多了个由TIM_OCInit变成了,TIM_OC1Init、TIM_OC2Init、TIM_OC3Init、TIM_OC4Init四个函数来设定。
应用就没啥好说的,设一设,然后记得 TIM_CtrlPWMOutputs(TIMx,ENABLE); 就这样输出了。
PS:在做可调的PWM输出 最好以PSC 来改频率 CRRx改占空比。如果把PSC定死了,那么不管要修改频率还是占空比都要把ARR和CCRx 的值都重新算一遍。
无线承载网络(Wireless Hosted Network)是Windows 7和安装有 WLAN 服务的Windows Server 2008 R2中一项新增的WLAN特性。
通过此特性,Windows 计算机能通过一块物理无线网卡以客户端身份连接到(由物理设备提供的)硬AP,同时又能作为软AP,允许其它设备与自己连接.
为了不让有些人叫板说:“这是个伪技巧,XP,vista里也可以实现无线共享啊”,所以我特此申明,XP,vista里利用传统的临时无线网(即Ad Hoc模式)来实现的,临时无线网(即Ad Hoc模式)是一种点对点网络,类似于有线网中的“双机互联”,虽然也能实现互联网共享,但主要用于两个设备临时互联,并且有的设备(如采用Android系统的设备)并不支持连接到临时无线网。还有一个很严重的问题,由于一块无线网卡只能连接到一个无线网络,因此如果通过无线网卡连接到 Internet,就不能再使用这个无线网卡建立临时网络,共享 Internet 了。而无线承载网络的原理就不一样了。它是通过把物理网卡虚拟一块虚拟网卡,从而模拟软AP的功能。所以当你物理网卡连在真正的无线路由时,可以通过模拟的软AP(软路由)供其他电脑上网。
第一,一管理员身份运行命令提示符(开始菜单——所有程序——附件,找到命令提示符,右键单击它,选择“以管理员身份运行”,在弹出的用户控制窗口中单击“是”。)然后输入命令:
netsh wlan show drivers
如果“支持的网络承载”一栏为“是”,那么你的网卡使用“软AP”功能。
第二,输入如下命令,启用并设定“虚拟Wifi网卡”模式:
netsh wlan set hostednetwork mode=allow ssid=”shadowhack” key=88888888
其中
Mode:是否启用虚拟Wifi网卡,改为disallow则为禁用,虚拟网卡即会消失。
Ssid:指定无线网络的名称,最好为英文。
Key:指定无线网络的密码。该密码用于对无线网进行安全的WPA2加密,能够很好的防止被蹭网。
以上三个参数其实可以单独使用,例如只使用 mode=disallow 可以直接禁用虚拟Wifi网卡。
3. 启用“Internet连接共享(ICS)”
为了与其他计算机或设备共享已连接的互联网,我们需要启用“Internet连接共享”功能。打开“网络和网络共享中心”窗口——“更改适配器设置”,右键单击已连接到Internet的网络连接,选择“属性”,切换到“共享”选项卡,选中其中的复选框,并选择允许其共享Internet的网络连接在这里即我们的虚拟Wifi网卡
4. 开启无线网络
继续在命令提示符中运行以下命令:
netsh wlan start hostednetwork
即可开启我们之前设置好的无线网络(相当于打开路由器的无线功能。同理,将start改为stop即可关闭该无线网)。
关于I2C 学习的时候介绍得最多的就是24C02 这里存储EEPROM了,但学的时候基本只是讲讲简单的I2C 的总线数据传输而已,即使先gooogle上搜索也绝大部分这这样的文章,很少有说到如何在实际情况中如何使用的程序。
24Cxx系列数据块存储时也是比较讲究的,
图为 几类不同容量的芯片的存储空间结构,24C16以下空间的大于8位后的寻址高位地址在片选地址中选择,详细看芯片手册。另外要注意的就是字节页,一次连续写入的数据量不能超过一页的数据量。有些老款的芯片甚至不支持跨页写入。为了适用也参照不跨页写入的方法写这个程序。而读取数据没有这个限制,只要单片机开辟的缓存够大,可以一直连续读下去。
/*****24Cxx Seriel EEPROM*************************/ #define EEPROM 8 /**此处定义适用的芯片型号****/ /******** 01 -> 24C01; 02 -> 24C02; 04 -> 24C04; 08 -> 24C08; 16 -> 24C16; 32 -> 24C32; 64 -> 24C64; 128 -> 24C128; 256-> 24C256; 512 -> 24C512; */ #if EEPROM==1 #define PAGE_SIZE 8 #define EE_SIZE 0x007F #elif EEPROM==2 #define PAGE_SIZE 16 #define EE_SIZE 0x00FF #elif EEPROM==4 #define PAGE_SIZE 16 #define EE_SIZE 0x01FF #elif EEPROM==8 #define PAGE_SIZE 16 #define EE_SIZE 0x03FF #elif EEPROM==16 #define PAGE_SIZE 16 #define EE_SIZE 0x07FF #elif EEPROM==32 #define PAGE_SIZE 32 #define EE_SIZE 0x0FFF #elif EEPROM==64 #define PAGE_SIZE 32 #define EE_SIZE 0x1FFF #elif EEPROM==128 #define PAGE_SIZE 64 #define EE_SIZE 0x3FFF #elif EEPROM==256 #define PAGE_SIZE 64 #define EE_SIZE 0x7FFF #elif EEPROM==512 #define PAGE_SIZE 128 #define EE_SIZE 0xFFFF #endif
头文件可以写成预编译模式,方便移植后修改,PAGE_SIZE为一页的存储量,EE_SIZE为芯片的存储量,而后一些程序的判断也根据选择的存储芯片来判断。
顶层用于外部程序调用的函数只有两个,读和写两个情况而已
unsigned char EEPROM_Write(unsigned char* pBuffer,unsigned int WriteAddress,unsigned char NumbyteToWrite); unsigned char EEPROM_Read(unsigned char* pBuffer,unsigned int ReadAddress,unsigned char NumbyteToWrite);
传递函数有三个:
pBuffer:要存储或读出来的数据所在的变量存储区字符串头指针;
WriteAddress/ReadAddress:要存入EEPROM所在的存储空间的第一个存储空间地址;
NumbyteToWrite:数据写入或读出的字节个数;
这样的应用比较简单 例如在头文件中分配了两类数据的存储空间起始地址DATA1、DATA2
#define DATA1 0x0010
#define DATA2 0x0050
存储数据所在缓存 EE_Buffer[20],应用程序如下写法:
EEPROM_Write(EE_Buffer,DATA1,20);
这样EE_Buffer内的数据便被写入EEPROM中 0x10~0x30 的数据存储空间中了。
合理的分配陪EEPROM 的存储空间对数据管理非常重要。甚至于可以作为一个小型黑匣子一样。
unsigned char EEPROM_Write(unsigned char* pBuffer,unsigned int WriteAddress,unsigned char NumbyteToWrite) { unsigned char TempBuffer,Temp2Buffer; if((WriteAddress+NumbyteToWrite) > EE_SIZE) //判断是否超出存储空间 { return 0; } else { IIC_WriteBuffer(pBuffer,WriteAddress,NumbyteToWrite); IIC_WriteBuffer(pBuffer,WriteAddress,NumbyteToWrite);// 连续写入两次避免因EMC等因素造成的写入失败情况 IIC_ReadBuffer(&TempBuffer,WriteAddress+NumbyteToWrite-1,1);//读取eeprom 的数据与缓存中的数据对比 相同为确认写入成功 Temp2Buffer=*(pBuffer+NumbyteToWrite-1); if(TempBuffer==Temp2Buffer) return 1; else return 0; } } unsigned char EEPROM_Read(unsigned char* pBuffer,unsigned int ReadAddress,unsigned char NumbyteToWrite) { if((ReadAddress+NumbyteToWrite) > EE_SIZE) { return 0; } else { IIC_ReadBuffer(pBuffer,ReadAddress,NumbyteToWrite); IIC_ReadBuffer(pBuffer,ReadAddress,NumbyteToWrite); return 1; } }
接下来的是是IIC_ReadBuffer、IIC_WriteBuffer,两个函数主要是对存入数据的处理,如页面内写入,超过页面数量的数据处理等,我这里把函数定义为static 函数只能对内部应用,外部只能调用上面的两个函数,累似于API函数一样,这也可以避免不必要的程序调用书写。IIC_ReadBuffer函数相对简单,因为读取没有对页面的限制,可以无限制的读下去。
static void IIC_ReadBuffer(unsigned char* pBuffer,unsigned int ReadAddress,unsigned char NumbyteToWrite); static void IIC_WriteBuffer(unsigned char* pBuffer,unsigned int WriteAddress,unsigned char NumByteToWrite); void IIC_ReadBuffer(unsigned char* pBuffer,unsigned int ReadAddress,unsigned char NumbyteToWrite) { // u8 NumOfPage=0,NumOfSingle=0;count=0 Part=0, u8 PageAddress=0; /******pageAddress is over 8bit***********/ #if EEPROM < 32 PageAddress=(u8)(ReadAddress>>7)&0x0E|ReadAddress_EEPROM; #else PageAddress=WriteAddress_EEPROM; #endif IIC_ReadPage(pBuffer,PageAddress,ReadAddress,NumbyteToWrite); }
void IIC_WriteBuffer(unsigned char* pBuffer,unsigned int WriteAddress,unsigned char NumByteToWrite) { u8 NumOfPage=0,NumOfSingle=0; //,count=0 u16 Part=0;// u8 PageAddress=0; /******pageAddress is over 8bit***********/ /******判断存储地址是否超过8位************/ #if EEPROM < 32 PageAddress=(u8)(WriteAddress>>7)&0x0E|WriteAddress_EEPROM; #else PageAddress=WriteAddress_EEPROM; #endif /*******判断起始地址与跨页地址的字节个数******/ Part=WriteAddress/PAGE_SIZE; if(Part!=0) { Part=PAGE_SIZE*(Part+1)-WriteAddress; } else { Part=PAGE_SIZE-WriteAddress; } if(Part >= NumByteToWrite) /***写入的数据个数小于跨页剩余的个数可直接写入 ***/ { IIC_WritePage(pBuffer,PageAddress,WriteAddress,NumByteToWrite); } else /***1.写入的数据个数大于跨页剩余的个数先把剩余的跨页个数填充满 ***/ { NumOfPage = (NumByteToWrite-Part)/PAGE_SIZE; NumOfSingle = (NumByteToWrite-Part)%PAGE_SIZE; pBuffer = IIC_WritePage(pBuffer,PageAddress,WriteAddress,Part); NumByteToWrite -= Part; WriteAddress += Part; while(NumOfPage--) /***2.按计算的数据量占页面数,连续写入页面*******/ { pBuffer = IIC_WritePage(pBuffer,PageAddress,WriteAddress,PAGE_SIZE); WriteAddress += PAGE_SIZE; // pBuffer += PAGE_SIZE; } if(NumOfSingle!=0) /***3.补充页面写完后超出的不足一页数据量的数据***/ { IIC_WritePage(pBuffer,PageAddress,WriteAddress,NumOfSingle); } } }
剩下的是IIC_WritePage()、IIC_ReadPage()两个函数是芯片的IIC通讯底层函数,根据单片机的IIC通讯模式写入即可。以上的程序可通用到任何24Cxx 系列所应用的程序。
设计好一阵子了,给朋友送去打板子,中途折腾了一些别的事情,弄到现在才到我手里,效果还好的。自交通讯延时50ms约有千分之五的失败率,说实在的没有预想中的好
实物照
原理图满大街都有的,这里也发上来让人参考一下吧