wjyspring 发表于 2007-10-7 19:52:52

10.1长假结束,决定用一个月做马潮老师讲义上的主要实验。

第一个实验:设计一个4种闪烁方式交替循环的彩灯,闪烁方式见图6-7。

(实验要求见讲义第6章的第9页,简记为P6-9,以后引用讲义内容均按此标记)

源代码:
/*********************************************
Writer:wjyspring
file name                       : demo_6_9.c
Chip type         : ATmega16
Program type      : Application
Clock frequency   : 4.000000 MHz
Memory model      : Small
External SRAM size: 0
Data Stack size   : 256
*********************************************/

#include <mega16.h>
#include <delay.h>
//#include <math.h>   
#include <stdlib.h>   
void main(void)
{   
char i=0;
char position = 0;        // position为控制位的位置

PORTA=0xFF;        // PA口输出全1,LED全灭
DDRA=0xFF;                // PA口工作为输出方式
            
while(1)
{
for(i=0;i<16;i++)                   //左移循环两轮
{
        PORTA = ~(0x80>>position);                       
        if (++position >= 8) position = 0;
        delay_ms(500);
}   
for(i=0;i<16;i++)                  //右移循环两轮
{
        PORTA = ~(1<<position);               
        if (++position >= 8) position = 0;
        delay_ms(500);
}
   for(i=0;i<16;i++)                  //间隔点亮明暗交替16次
{
        PORTA = 0xaa;               
        delay_ms(500);
        PORTA = ~0xaa;               
        delay_ms(500);
}   
for(i=0;i<16;i++)   //随机点亮16次
{
      PORTA =rand();
      delay_ms(500);
}   
}
}

关于rand和srand函数的说明:rand的内部实现是用线性同余法做的,它不是真的随机数,只不过是因为其周期特别长,所以有一定的范围里可看成是随机的,rand()会返回一随机数值,范围在0至RAND_MAX 间。在调用此函数产生随机数前,必须先利用srand()设好随机数种子,如果未设随机数种子,rand()在调用时会自动设随机数种子为1。rand()产生的是假随机数字,每次执行时是相同的。若要不同,以不同的值来初始化它.初始化的函数就是srand()。

请菜鸟思考,在这个实验要求中(见讲义),我们并不需要用到srand函数。这是为什么?呵呵。

wjyspring 发表于 2007-10-7 20:20:52

第二个实验:讲义P6-15,控制一个8段数码管循环显示“0”-“F”16个十六进制的数字,每个字符显示1秒钟,并且在显示的1秒内,数码管的小数点(P段)要亮0.5s,灭0.5s。

源代码:
/*********************************************   
writer            :wjyspring
file name                 :demo_6_15.c
Chip type         : ATmega16
Program type      : Application
Clock frequency   : 4.000000 MHz
Memory model      : Small
External SRAM size: 0
Data Stack size   : 256
*********************************************/

#include <mega16.h>
#include <delay.h>

flash char led_7={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,
                      0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
bit point_on = 1;
void main(void)
{
        char i = 0;

        PORTA=0xFF;
        DDRA=0xFF;

        while (1)
    {
                for (i=0;i<=15;i++)
                {
                        PORTA = led_7;
                        if (point_on) PORTA |= 0x80;
                        delay_ms(500);      
                        point_on = ~point_on;   
                         PORTA = led_7;
                        if (point_on) PORTA |= 0x80;
                        delay_ms(500);
                        point_on = ~point_on;
                }
               
    };
}

machao 发表于 2007-10-7 23:14:25

另外建议你把我的例程后面的问题与思考仔细想想,然后把答案贴上来,大家讨论。

lvhaian 发表于 2007-10-8 01:44:52

给新人一些建议.

在大家编程之前,先去看看华为公司的软件编程规范,网上很容易看到的.

最起码我看到上面的软件例子的时候就感觉蛮便扭的.

简单看了两眼,不像出自一个单片机软件高人的手笔.变量命名规则有待改进.char之类的和编译器有关的东西没有用宏,等等.
还有好几处不合适的地方,我就不指出了.

虽然大家会认为这只是个小实验,随便点无所谓.

但一个在软件上有些资历的人编程会有一些风格的,其实只要有一点点地和自己风格不一样的地方,都会让自己非常的不舒服.一定会改掉的,所以我们基本能从简单的一小段代码中看出一个人对程序的理解度,和写程序的实力,更能看出一个人的阅历.

lvhaian 发表于 2007-10-8 02:06:25

一个资深的软件设计师形成的5个阶段:

1: 入门阶段: 读大量的程序,能够自己修改和拼凑出一个能实现功能的程序. 可以完成简单的软件工作.
2: 合格阶段: 熟知各种知名的程序风格,形成自己的风格,并能够独立完成一个超过1W行代码的项目,基本无错误.
3: 优秀阶段: 熟读各种系统内核源码,能够正确评判代码的质量,效率,优缺点. 十分考究冗余性,扩展性,纠错性等,能够在大型软件项目中担任核心成员.
4: 核心阶段: 能够自己编写出优秀操作系统之类内核源码,能够带领团队完成大型软件工程.
5: 专家阶段: 可以有创立一种更加优秀的软件思想的专家.能够权威并且正确无误的批判所有软件质量的专家.

tdmi 发表于 2007-10-8 09:26:38

同意3楼,养成良好的习惯有时候比掌握一门技术更重要,尤其对初学者

wjyspring 发表于 2007-10-8 09:26:41

感谢以上两位的指教!
做第三个实验P6-17例6.5 六位LED数码管动态扫描控制显示设计(一)出现了点问题。。。用马老师的代码昨天晚上能够从时间初始值23:58:55正常运行,今天再做的时候6个数码管显示全为“0”,2个小数点位还在每隔1秒闪烁。怀疑数码管坏了,重做第2个实验,结果正常。不知道问题在哪儿。


http://cache.amobbs.com/bbs_upload782111/files_8/ourdev_175744.JPG

wjyspring 发表于 2007-10-8 15:03:03

第3个实验的问题还没有解决,先贴出第4个实验:例6.7 8*8点阵LED显示控制设计
思考与实践
1、本例程与数码管显示程序有非常多的类似地方,请读者自己分析程序的功能。

2、请给出程序中的时间分配情况,如何调整箭头移动的速度的快慢,而又不影响正常的显示?
   答:将马老师源代码倒数第7行“if (++time_counter >=4) ”改成“if (++time_counter >=10) ”
       就可以放慢移动速度了。

3、如果将display()函数中的语句“PORTC = ~(1<<i);”改为“PORTC = ~(1<<(7-i));”,显示有何变化?
   答:箭头方向由向上变为向下

4、设计一个水平移动的8*8点阵广告,能够显示“今天YOU ARE OK?”

   我偷点懒,实现了水平向右显示“今天”。码值表如下
http://cache.amobbs.com/bbs_upload782111/files_8/ourdev_175825.JPG
源代码如下:
/*********************************************
file name         : jintian.c
Chip type         : ATmega16
Program type      : Application
Clock frequency   : 4.000000 MHz
Memory model      : Small
External SRAM size: 0
Data Stack size   : 256
此程序的作用是在8X8点阵上实现“今 天”的右移
*********************************************/

#include <mega16.h>
#include <delay.h>


flash char char_16={0xEF,0xEF,0xD7,0xA1,0x16,0xD7,0xEF,0xF7,0xff,0xee,0xad,0xab,0x87,0xab,0xad,0xee};//其中0xff为一空格

void display(char col)
{
        char i;
        for (i=0;i<=7;i++)
        {
                if (col <= 15)
                        PORTC = char_16;
                else
                        PORTC = 0XFF;
                PORTA = 1<<i;//在这里可以修改移动方向
                delay_ms(2);
                PORTA = 0x00;
                if (++col >= 20 ) col = 0;                
        }
}

void main(void)
{
        char time_counter,i = 0;
        PORTC=0xFF;
        DDRC=0xFF;
        PORTA=0x00;
        DDRA=0xFF;

        while (1)
        {
                display(i);
                delay_ms(9);
                if (++time_counter >= 20)//在这里可以修改移动速度
                {
                        time_counter = 0;
                        if(++i >= 20) i=0;
                }
        };
}

wjyspring 发表于 2007-10-8 18:05:38

第5个实验:P6-26 例6.8 16*2标准LCD字符显示器应用设计
先指出马老师讲义上的一个打印错误:P6-26关于void lcd_gotoxy(unsigned char x, unsigned char y)的说明,
“该函数将显示位置定位于第x行的第y列的位置处。”应该更正为“该函数将显示位置定位于第y行的第x列的位置处。”

我在实验板上完成了讲义中的两个实验,现贴出我自己写的一个小程序,
这个程序的功能是在1602上显示“User define arrow:箭头符号”,已经在板子上运行成功。
其中的一个函数void define_char(byte flash *pc,byte char_code)我没有弄懂,请求过来人注解。谢谢!

/*
file name         : arrow.c
Chip type         : ATmega16
Program type      : Application
Clock frequency   : 4.000000 MHz
Memory model      : Small
External SRAM size: 0
Data Stack size   : 256
*/   

/* 包含头文件 */
#include <mega16.h>
#include <lcd.h>
/* LCD 连接 PORTC */
#asm
.equ __lcd_port=0x15 ;PORTC
#endasm

typedef unsigned char byte;
/* 自定义字符的点阵数据,一个指向右上角的箭头 */
flash byte char0={
0b0000000,
0b0001111,
0b0000011,
0b0000101,
0b0001001,
0b0010000,
0b0100000,
0b1000000};

/* 定义自定义字符 ,以下六行请求过来人注释,谢谢!*/
void define_char(byte flash *pc,byte char_code)
{
   byte i,a;
   a=(char_code<<3) | 0x40;
   for (i=0; i<8; i++) lcd_write_byte(a++,*pc++);
}

void main(void)
{
   /* 初始化2 行16列LCD */
   lcd_init(16);
   /* 定义自定义字符0 */
   define_char(char0,0);
   /* 写显存 */
   lcd_gotoxy(0,0);
   lcd_putsf("User define arrow:");
   /* 显示自定义字符0 */
   lcd_putchar(0);
   while (1);
}

machao 发表于 2007-10-8 22:43:30

你这样做收获不会很大,要仔细分析程序,真正了解程序的思路和方法。做到看程序后就能知道85%(甚至是100%)的运行情况,然后下载验证。

例如,你回答的:

2、请给出程序中的时间分配情况,如何调整箭头移动的速度的快慢,而又不影响正常的显示?
   答:将马老师源代码倒数第7行“if (++time_counter >=4) ”改成“if (++time_counter >=10) ”
       就可以放慢移动速度了。

3、如果将display()函数中的语句“PORTC = ~(1<<i);”改为“PORTC = ~(1<<(7-i));”,显示有何变化?
   答:箭头方向由向上变为向下

是读程序就分析出来的,还是看到现象后得出的?时间分配情况应该仔细分析:LED扫描的时间;字符移动的时间;是否有相互的影响;时间应该精确到ms。

==================================================================================================================
下面对你7楼的“今天”右移程序做个点评,请参考。

1。比箭头的上下移动有进步,知道将PA和PC换用,比我大部分的学生做的好。(得75分)
   我的学生他们通常直接使用箭头程序,然后把板顺时针转90度,说实现了右移,偷懒的做法(只能得30分)。
   当然在实际产品的设计中,应该使用把LED转90度的硬件设计,使软件设计方便。
   但在这里就是偷懒了,因为我的硬件已经设计完成了,如果是一个大型广告牌,你总不能把它转90度安装吧。这个练习主要是训练软件设计的,简单照搬程序不提倡。

2。为什么你只能得75分呢?不知道你是否观察到你的LED有些列亮,有些列暗,例如某列上有多个LED亮的话,该行的平均亮度就比较暗。原因再于你没有充分考虑和发挥I/O的驱动能力。
   在你的程序中,PA口输出1,负责1列,该列中如有8个LED亮,PC输出全0(所以你的码值表PC是取反的)。8个LED全亮,需要8*5=40ma电流,而AVR的I/O输出“1”时,只能输出20ma电流,所以LED就不够亮。而AVR的I/O口输出“0”时,最大的灌电流可以达到40ma。所以最好还是一行一行的扫描,但如何巧妙的设计程序就看你了。当然就比箭头的上下移动要复杂了。
   作为程序的设计练习,建议你再考虑考虑,争取得到100分。

3。这个例子也说明硬件设计的重要性。如果硬件设计的好,软件的编写可以方便很多,这也是嵌入式系统设计的特点,所以不要忽视硬件的设计和技巧,这也是一般人不重视的。

4。已经有人将我的书(讲义)是入门的,我也认为是入门的,但象我这样的入门深度,恐怕是其它大多数的入门书所不能及的。所以请你仔细、认真的、踏踏实实的入门。

5。到目前还没有几个(包括我上课的学生)能真正的深入思考和仔细和全面的回答我讲义中的问题,例子也是模仿、照搬的多,希望你不是这样的。

wjyspring 发表于 2007-10-9 09:22:54

谢谢马老师指导!

wjyspring 发表于 2007-10-9 19:05:41

第4个实验:例6.7 8*8点阵LED显示控制设计 的补充

个人水平太烂,今天花了一天的时间,初步解决了马老师提出的每一列的亮度的问题。
虽然运行实现了,但感觉有些别扭。

以下是源代码:

/*********************************************
writer:         
file name         : jintian_liangdu.c
Chip type         : ATmega16
Program type      : Application
Clock frequency   : 4.000000 MHz
Memory model      : Small
External SRAM size: 0
Data Stack size   : 256
功能:实现“今天”右移。   
此程序解决了jintian.c中LED有些列亮,有些列暗的问题,
线路连接如下:
   JE1 - 8PA0 (M16)
   JE1 - 7PA1 (M16)
   JE1 - 6PA2 (M16)
   JE1 - 5PA3 (M16)
   JE1 - 4PA4 (M16)
   JE1 - 3PA5 (M16)
   JE1 - 2PA6 (M16)
   JE1 - 1PA7 (M16)

   JE2 - 1PC0 (M16)
   JE2 - 2PC1 (M16)
   JE2 - 3PC2 (M16)
   JE2 - 4PC3 (M16)
   JE2 - 5PC4 (M16)
   JE2 - 6PC5 (M16)
   JE2 - 7PC6 (M16)
   JE2 - 8PC7 (M16)
*********************************************/

#include <mega16.h>
#include <delay.h>
/*    码值表            0x10,0x18,0x34,0x4b,0xbc,0x08,0x08,0x10,       //今
                        0x00,0x3e,0x08,0x7f,0x08,0x14,0x22,0x41      //天*/                           
flash int rowcode[]= {0x0010,0x3e18,0x0834,0x7f4b,0x08bc,0x1408,0x2208,0x4110};

void display(char col)
{
char i;      

        for (i=0;i<=7;i++)
        {
          PORTA = rowcode>>col;
          PORTC = ~(1<<i);                  //行扫描
          delay_ms(2);
          PORTC = 0xFF;
        }   
        PORTC = 0xFF;   

}


void main(void)
{
        char time_counter,i = 0;
        PORTA=0x00;
        DDRA=0xFF;
        PORTC=0x00;
        DDRC=0xff;

        while (1)
        {
                display(i);
                delay_ms(9);
                if (++time_counter >= 4)
                {
                        time_counter = 0;
                        if(++i >= 16) i=0;
                }
        };
}

machao 发表于 2007-10-9 22:42:20

还是不符合要求,如果是10个字的话,你的数据结构根本不能使用。

你要设计使用一个好的数据结构,使编写的程序为通用的程序,可以满足1-N个字的右移(只要改动文字的定义,和说明N是几就可以),再考虑考虑。

wjyspring 发表于 2007-10-12 20:13:16

这两天老师和我商量,要开始做一个项目。实现烤烟的自动控制,这个项目我在暑假已经用51实现了,但还不够完善。
现在打算用MEGA64或MEGA128做,因此“10.1长假结束,决定用一个月做马潮老师讲义上的主要实验。”这个帖子可能耽误,
不能及时更新。深表歉意。

这个项目很小,只需要用到AVR的I/O口和定时器,实现温度湿度采集,数码显示,语音提示,
2个220V 和1个380V的机器开关控制。


知道这样不坚持系统学习很浮躁。。。但老师交代的事,迫不得以。以后还有很多地方需要向马老师请教。

谢谢!

wjyspring 发表于 2007-10-12 21:18:05

马老师能不能给个CodeVisionAVR的序列号?试用版的好象有很多函数用不了,比如说温度函数。谢谢!
我的邮箱 wujunyongjior618@sina.com

machao 发表于 2007-10-14 00:32:56

http://file.mcu123.com/

mxjyjs 发表于 2007-10-25 19:59:02

马潮老师讲义在哪能下载,谢谢!

machao 发表于 2007-10-25 20:22:22

转到“马潮老师专栏(AVR)”中,就在你的头上叫你呢。

小声讲一下,可能你学AVR很吃力,因为这个网站的东西和内容你都不会自己仔细了解的话,AVR的手册你是不会很好的看了。
页: [1]
查看完整版本: 10.1长假结束,决定用一个月做马潮老师讲义上的主要实验。