最新日志

发表于:2008-9-3 10:42:24
标签:SD  驱动  Mega16  

2

【原创】Mega16读写SD卡

这是我这几天学习SD卡读写的结果,参考了网络上的一些资料,上电初始化数据后读取容量制造商信息,然后往块2写入512字节数据然后读出,串口显示。硬件是Mega16外部7.37628M晶体SPI方式读写。

点击看大图

点击看大图

项目工程下载:rar

点击此处查看原文 >>

系统分类: 单片机   |    用户分类:    |    来源: 原创

评论(1) | 阅读(151)
发表于:2008-8-27 16:51:51
标签:sd  card  资料  

1

【整理】SD学习卡资料

最近在学习单片机读写SD卡,先分享一下我在网络上找的有关SD的资料。

sandiskpdf

sd memory cardpdf

sd spi翻译.part1rar

sd spi翻译.part2rar

sd spi翻译.part3rar

 

 

点击此处查看原文 >>

系统分类: 单片机   |    用户分类:    |    来源: 整理

评论(0) | 阅读(87)
发表于:2008-8-18 9:27:57
标签:灰度  595  LED  

1

[学习]用595驱动LED实现灰度调节

前一段时间在ouravr论坛里闲逛的时候看到一篇关于用595驱动LED现实等级灰度的求助贴,楼主的意思是用595驱动LED,并且每个LED的亮度值可以随意调节,来达到不同的灰度。我感觉挺有意思的,用595驱动LED并不难,整体亮度调节也不难,再用PWM控制所有595OE就可以了,单个LED灰度的调节就比较麻烦了。有一位叫“polarbear 枫叶”回帖提出的思路比较简单新颖,我按照他的思路试验了,感觉效果还不错!硬件是M48+2片595+16个LED,用的硬件ISP主机模式。

先上图再说:

点击看大图

如果不过瘾这还有一段视频:

rar rar rar rar

现在来说说实现的方法吧,转载一下枫叶的原话:

16个灰度,也就是 0--15,用4BIT来表示, 8-4-2-1

PWM产生4个联系不同占空比的脉冲

T8        8/16                
对应
BIT8        
T4        4/16                
对应
BIT4        
T2        2/16                
对应
BIT2        
T1        1/16                
对应
BIT1        

8/16
表示的是把PWM的周期划分为16份,其中量的周期占8份,其他雷同


当这4个脉冲运行后,由于人的生理特点。也会出现需他的灰度;

同上面的方法比较,它需要4次个周期人眼才能感觉出灰度;

但是对PWM的要求就很低;比如256种灰度,不过送8次,1024也不过要10

大大减低了对硬件的要求,现在基本都是使用这种方法;


在一个595+出现不同的灰度,就必须结合下面说的东东;

把一个灰度分解成4

例如灰度9
 1001
T8        8/16                
对应
BIT8        
T4        
不亮                对应
BIT4        
T2        
不亮                对应
BIT2        
T1        1/16                
对应
BIT1
所以我们的各个灰度分解为4帧,送4次都595,就可以了

例如在1595上出现下面不同灰度的4个点,(就以4个点举例,)

4
个点的灰度

3,12,10,7
转化为BIN

0011  1100  1010 0111
8-4-2-1分割出来,得到独立的4

BIT8
0      1     1   0
BIT4
0       1     0   1
BIT2
1      0      1   1
BIT1
1      0      0    1

步骤:

1.
BIT8的数据送到595,PWM控制OE的脉冲为
T8
2.
BIT4的数据送到595,PWM控制OE的脉冲为
T4
3.
BIT2的数据送到595,PWM控制OE的脉冲为
T2
4.
BIT1的数据送到595,PWM控制OE的脉冲为
T1


经过4帧的时间叠加后,就得到不同的灰度。

 

原帖地址:http://www.ouravr.com/bbs/bbs_content_all.jsp?bbs_sn=985613

我的程序下载(WINAVR GCC + m48Dev)rar

 

 

点击此处查看原文 >>

系统分类: 单片机   |    用户分类:    |    来源: 整理

评论(0) | 阅读(148)
发表于:2008-7-20 8:44:32
标签:QFP  DIP  转换板  

1

[原创]show一下刚做好的QFP转DIP小板

在搞单片机的时候经常会用到贴片的TQFP封装,但是在试验阶段焊接太麻烦,位方便我就自己做了QFP转DIP小板,它可以将TQFP32,44,64脚的贴片转换成相应管脚的DIP,在一块板子上就可以实现三种封装的转换很方便的,不多说了,还是赶紧上图:

点击看大图

点击看大图

点击此处查看原文 >>

系统分类: 单片机   |    用户分类:    |    来源: 原创

评论(4) | 阅读(202)
发表于:2008-7-15 16:32:42
标签:PS/2  键盘  Meag48  AVR  串口  

2

[原创]Mega48解码PS/2键盘+串口显示

前几天在单位发现了一个古董机级的键盘,估计是以前X86机器上的键盘,虽然出的早但键盘依然很结识,拿起来很有手感(很重金属材料用的不少),连接上电脑居然还能使用,不过遗憾的是有现按键在XP系统下识别不了。仍了怪可惜的,作为研究PS2协议还是很不错的,于是乎就查资料写了个PS/2键盘的小程序,AVR GCC环境下编写,单片机用是AVR的Mega48v,硬件平台还是我的m48Dev 外置7.3728M晶体,PS/2键盘与单片机连接如下:

PS/2_DATA -------------------PC0

PS/2_CLK----------------------INT0

PS/2_VCC----------------------+5V

PS/2_GND----------------------GND

串口接收截图

点击看大图

部分核心代码:

/************************************************************************
*名称: unsigned char PS2_KeyDeCode(unsigned char bKeyCode)     
*功能: PS2键盘解码程序                     
*参数: bKeyCode 键盘码        
*返回: 按键的ASIIC码                                     
************************************************************************/
unsigned char PS2_KeyDeCode(unsigned char bKeyCode)
{
 unsigned char i;
 if (!PS2KeyStatus.bBreakFlag)//通码
 {
  switch (bKeyCode)//开始翻译扫描码
  {
   case 0xF0: //键盘释放随后的一个字节是断码
   {
    PS2KeyStatus.bBreakFlag = 1;//断码标志置位
    break;
   }
   case 0x12:    //左shift键按下
   {
    PS2KeyStatus.bShiftFlag = 1; //shift标志置位
    break;
   }
   case 0x59:    //右shift键按下
   {
    PS2KeyStatus.bShiftFlag = 1; //shift标志置位
    break;
   }   
   default:       
   { 
    PS2KeyStatus.bBreakFlag = FALSE;
    if(!PS2KeyStatus.bShiftFlag) //如果shift键没有按下
    {  
     for(i = 0; i < 65; i++)//查表找按键ASIIC码
     {
      if(pgm_read_byte(PS2CodeUnShift[i]) == bKeyCode)
      {
       PS2KeyStatus.bKeyAsiic =
         pgm_read_byte(PS2CodeUnShift[i] + 1);
       PS2KeyStatus.bKeyNewFlag = TRUE;
       break;
      }
     }
    }
    else  //如果shift键按下
    {       
     for(i=0; i < 65; i++)//查表找按键ASIIC码
     {
      if(pgm_read_byte(PS2CodeShift[i]) == bKeyCode)
      {
       PS2KeyStatus.bKeyAsiic =
         pgm_read_byte(PS2CodeShift[i] + 1);
       PS2KeyStatus.bKeyNewFlag = TRUE;
       break;
      }
     }
    }
    break;
   }
  }
 }
 else //断码
 {
  PS2KeyStatus.bBreakFlag = 0; //将断码标志复位
  switch (bKeyCode)  //检测shift键释放
  {
   case 0x12 :      //左shift键
    PS2KeyStatus.bShiftFlag = 0;
    break;
   case 0x59 :   //右shift键
    PS2KeyStatus.bShiftFlag = 0;
    break;
   default:
    break;
  }
 }

下载完整代码:rar
另附PS/2协议中文版pdf

 

点击此处查看原文 >>

系统分类: 单片机   |    用户分类:    |    来源: 原创

评论(2) | 阅读(204)
发表于:2008-6-7 17:00:19
标签:固件手册  中文  STM32  

2

[整理]STM32固件库中文手册

        我以前在mxchip上下载的STM32固件库的中文手册,前天一位网友还问我要过,不过发现mxchip网站上好像没有下载地址了,现发到博客上供大家下载参考!

资料大小超过1M最大限制,弄了两压缩包,下载后一起解压就好了。

基于ARM的32位MCU STM32F101xx 和 STM32F103xx固件库.part1.rarrar

基于ARM的32位MCU STM32F101xx 和 STM32F103xx固件库.part2.rarrar

 

 

 

点击此处查看原文 >>

系统分类: 单片机   |    用户分类:    |    来源: 整理

评论(5) | 阅读(569)
发表于:2008-6-6 11:17:22
标签:STM32  USB  

4

[心情]STM32的USB固件库看起来头大

最近一直在学习USB,前段时间在看USB协议方面的资料,现在看STM32的USB固件库,不看不知道一看吓一跳,好复杂哦(俺是新手刚接触USB)!据21ic的香水城斑竹说这个USB架构已经经历了ARM7-ARM11的考验应该是很成熟稳定的架构了,不我对于我等新手来说看起来还是比较吃力,对于它的整体运行流程和思路有点晕。MXCHIP翻译的中文资料讲的也不很详细,也许这是我个人感觉,或许高手们不这样认为,希望能已经搞定USB的朋友交流学习一下,相互进步!

送上一份STM32 USB固件的中文资料:pdf

点击此处查看原文 >>

系统分类: 单片机   |    用户分类:    |    来源: 原创

评论(6) | 阅读(564)
发表于:2008-5-23 14:54:53
标签:大小端模式  数据结构  

0

[转帖] 大小端模式的区别

   最近在学习USB,在看Keil C51代码的时候发现从PC机接收的USB数据在Keil C51环境里要交换高低字节,这是因为Keil的数据结构是大端模式,对于大端模式不是很清楚后来网上搜索发现有一篇文章介绍的比较详细,不敢独享贴出来大家学习。
   所谓的大端模式,是指数据的低位(就是权值较小的后面那几位)保存在内存的高地址中,而数据的高位,保存在内存的低地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;
   所谓的小端模式,是指数据的低位保存在内存的低地址中,而数 据的高位保存在内存的高地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。
   为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于 8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小 端存储模式。例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于 大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模 式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。
   下面这段代码可以用来测试一下你的编译器是大端模式还是小端模式:
short int x;
char x0,x1;
x=0x1122;
x0=((char*)&x)[0]; //低地址单元
x1=((char*)&x)[1]; //高地址单元
若x0=0x11,则是大端; 若x0=0x22,则是小端......
上面的程序还可以看出,数据寻址时,用的是低位字节的地址。
我用WINAVR GCC编程,利用上面的方法测试了一下发现是小端模式,所以我就不用交换字节啦!o(∩_∩)o...

点击此处查看原文 >>

系统分类: 嵌入式   |    用户分类:    |    来源: 转贴

评论(1) | 阅读(399)
发表于:2008-4-28 15:55:50
标签:PWM  转速  m48  AVR  

1

[原创]用M48的PWM功能控制风扇转速

   比较基础简单的试验,适合新手入门老鸟就不用看了,呵呵!

   ATMega48的定时器1工作在8位快速PWM模式,产生3906.25Hz的PWM波通过三极管来调整风扇的转速,风扇是CPU散热器上的直流12V风扇。程序是循环重低到高再到低来调整风扇转速。

点击看大图

代码如下:

/*************************************************************************
* Copyright (c) 2007 wormchen            
* All rights reserved             
* 文 件 名: main.c              
* 说    明: PWM 调整风扇转速                
*                            
* 主要硬件: AtemlMega48(内部1M)            
* 编译环境: WinAVR 20070525            
* 当前版本: 1.0               
* 作    者: wormchen               
* 完成日期: 2008年4月22日11:33:19          
* 取代版本: 1.0               
* 原作  者: wormchen              
* 完成日期: 2008年4月22日11:33:23          
************************************************************************/  
#include
#include
#include
unsigned int uchPWM = 0;

/************************************************************************
* 名称: void DelayMS(unsigned int uiMS)           
* 功能: 延时nms                     
* 参数: 无                                   
* 返回: 无                                     
************************************************************************/
void DelayMS(unsigned int uiMS)
 { 
  while(uiMS--)
   {
    _delay_loop_2(250); // 延时1ms(粗略)
   }
 }
/*************************************************************************
* 名称: void PORT_Init(void)              
* 功能: 端口初始化                    
* 参数: 无                                   
* 返回: 无                                     
*************************************************************************/ 
void PORT_Init(void)
 {
  PORTB &=  ~((1 << PB1) | (1 << PB2));
  DDRB = (1 << PB1) | (1 << PB2); 
 } 
/*************************************************************************
* 名称: void Timer1_Init(void)              
* 功能: TIMER1初始化                    
* 参数: 无                                   
* 返回: 无                                     
*************************************************************************/
void Timer1_Init(void)
{
 //快速PWM模式频率3906.25Hz
 TCNT1 = 0x0000;
 OCR1A = 0x0000;
 TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM10);
 //比较匹配清零TOP置位
 TCCR1B = (1 << WGM12) | (1 << CS10);
 //定时器1工作于8位快速PWM模式无分频

int main(void)
 {
  PORT_Init();
  Timer1_Init();
  while(1)
   {
    for(uchPWM = 0 ; uchPWM < 255; uchPWM++)
    {
     OCR1A = uchPWM;
     if(uchPWM == 0)
     {
      DelayMS(2000);
     }
     else
     {
      DelayMS(100);
     }     
    }
    for(uchPWM = 255 ; uchPWM > 0; uchPWM--)
    {
     OCR1A = uchPWM;
     if(uchPWM == 255)
     {
      DelayMS(2000);
     }
     else
     {
      DelayMS(100);
     }
     
    }
   }
 }

 

点击此处查看原文 >>

系统分类: 单片机   |    用户分类:    |    来源: 原创

评论(0) | 阅读(477)
发表于:2008-4-25 15:46:19
标签:RTC  STM32  学习笔记  

1

[原创]STM32学习笔记之—RTC

STM32学习笔记之—RTC

wormchenx@gmail.com

写这篇学习笔记的时候距上一篇笔记间隔的时间不短了,期间有网友关心询问为什么不更新文章,主要是这一段时间工作太忙了没有闲暇时间做下来学习,工作是重要的事情,不能把饭碗丢了啊o(_)o…,好了废话少说切入正题。

既然我们要使用RTC就要先对它有个大致的了解,知己知彼才能百战不殆嘛!STM32内部RTC功能非常实用,它的供电和时钟是独立于内核的,可以说是STM32内部独立的外设模块,有加上RTC内部寄存器不受系统复位掉电的影响,我们可以才用外部电池供电和32768表振晶体来实现真正RTC(实时时钟)功能。的这里引用手册里一段概述RTC由两个主要部分组成。第一部分(APB1接口)用来和 APB1总线相连。此单元还包含一组 16位寄存器,可通过 APB1总线对其进读写操作。APB1接口以 APB1总线时钟为时钟,用来与 APB1总线接口。

另一部分(RTC核)由一系可编程计数器组成,分成两个主要模块。第一个模块是 RTC的预分频模块,它可编程产生最长为 1秒的 RTC时间基准 TR_CLKRTC的预分频模块包含一个 20位的可编程分频器(RTC预分频器)。在每个TR_CLK周期中,如果在 RTC_CR 寄存器中设置相应允许位,则 RTC产生一个中断(秒中断)。第 2个模块是一个 32位的可编程的计数器,它可被初始化为当前的系统时间。系统时间以 TR_CLK增长并与存储在 RTC_ALR寄存器中的可编程的时间相比较,如果 RTC_CR控制寄存器中设置相应允许位,则比较匹配时将产生一个闹钟中断

对于第一次实用RTC的时候我们要对它进行配置一番,现在大致说一下(代码是通过调用RTC_Config函数来实现的):

1.      打开电源管理和备份寄存器时钟,提到备份寄存器这里要说一下,引用手册--备份寄存器是 10 16位的寄存器,可用来存储 20个字节的用户应用程序数据。他们处在备份域,当 VDD电源被断,他们仍然由 VBAT维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也会被复位”我们正式通过在备份寄存器写固定的数据来判断芯片是否第一次实用RTC,从而在系统运行RTC时提示配置时钟的。

2.      使能RTC和备份寄存器的访问(复位默认关闭)。引用手册--复位后,对备份寄存器和 RTC的访问被禁止,并且备份域被保护以防止可能存在的意外的写操作。电源控制寄存器(PWR_CR) DBP位必须被置 1,以允许访问备份寄存器和RTC.”因为程序要对RTC和备份寄存器操作,所以必须使能。

3.      选择外部低速晶体为RTC时钟,并使能时钟;

4.      使能秒中断,程序里在秒中断里置位标志位来通知主程序显示时间数据,同时在32位计数器到235959时清零;

5.      设置RTC预分频器值产生1秒信号计算公式 fTR_CLK = fRTCCLK/(PRL+1),我们设置32767来产生秒信号;

在这里要注意一下,所有在对RTC寄存器操作之前都要判断读写操作是否完成,也就是说当前是否有读写操作。系统内核是通过RTCAPB1接口来访问RTC内部寄存器的,所以在上电复位,休眠唤醒的时候,我们要先对RTC时钟与 RTC APB1时钟进重新同步,在同步完成后再对器进行操作,因为RTCAP1接口使用的系统APB1的时钟。上述配置在初次使用RTC时进行配置,在以后使用过程中,只要RTC外部电池持续供电,无论系统掉电还复位我们都无需重复配置,使用使能秒中断就可以了这一点很是方便嘿嘿...

在使用过程中我们通过读取32位可编程计数器的值来获取时钟信息,程序是通过串口2来向PC机发送数据来显示时钟的,并且还可以通过像STM32发送字符“S”来重新设置时钟数据,下面是几张调试的图片:

点击看大图

点击看大图

点击看大图