|
楼主 |
发表于 2008-12-3 12:06:46
|
显示全部楼层
示范程序提供如下功能:
使用万能电视遥控器控制小车开机,关机,前进,后退,左拐,右拐,停车,加速,减速,调节PWM周期等.
本开发板有如下功能:
1.红外接收,接收万能电视遥控器信号,简单实用.红外遥控用途极广泛,一定要掌握.红外线协议很多,可做的事情也很多.
2.利用单片机的空闲或掉电模式实现待机低功耗,简洁.
3.单片机控制开机,关机(待机),无硬开关,使用两个MOS管作为电源控制(输出电池电压,5V,3.3V).
4.单片机是STC12LE5410AD-35I-SOP28,工业级,代码空间是10K,内存512字节,有10位AD功能,还有SPI,PWM,PCA等功能,资源多,能容纳的程序可以相当复杂.
5.设计有声音功能,装有一片ISD1720芯片,能自由录音,实现很好玩的语音功能.
6.使用L293DD电机驱动芯片,实现2个H桥,能驱动两路电机.
7.提供LCD插座和模块,用的是5110显示屏.便宜实用.5110的屏也非常可靠.
8.提供NRF905无线模块的插座,此插座和LCD共用IO,只能使用其中一种,NRF905模块较为昂贵,仅提供一个插座,需要尝试的朋友请自行购买.
9.多余两个IO口分别带有AD功能和PWM/PCA功能,可灵活使用.
10.提供一条经过实际证明可靠的USB转串口线,3个用途:ISP下载,串口调试,5V电源,开发时非常方便.
11.提供充电插座和为单片机提供充电中断信号,单片机可以被唤醒以指示正在充电等控制.
12.本开发板的设计思想是:为小车平台提供最需要和实用的底层支持,可以被高级控制板(通过UART,制定一可靠协议)控制,实现更为复杂智能的功能(个人倾向用带摄像头的开发板做高级控制,用专门的传感器板功能太单一,也谈不上如何智能,且价格昂贵)
开发板指标:
1.电压,4.4v-16v.
2.电机最大持续驱动电流600ma.
3.待机电流0.5-2ma(具体依赖程序实现).
4.40秒录音(具体依赖采样率)
优点:
1.以产品的思路设计开发板,如红外接收,声音功能,充电,LCD功能都是实际产品必不可少的.
2.电路简洁,几乎没有多余的零件,实际测试非常稳定可靠.
3.利用单片机的低功耗模式,同时单片机IO控制多路电源(MOS管),以最简单的方法实现了待机,开机,实际表现非常之好,待机电流依赖程序精心编制程序,最小应该可以控制在ua级别.最大也就是2ma左右.
4.为小车平台提供低层支持,以后需要增加智能控制板,本开发板以组件的方式为高级控制板提供最基本的服务,高级控制板只需要在软件层面上考虑问题.所有设备不会冗余浪费.
5.掌握了本开发板很容易开发出实际产品.
产品清单:
1.调试好主板一块(除开NRF905插座之外的所有插头和插座,见图片)
2.LCD(使用5110屏幕)显示屏一块.
3.USB转串口一条,引出两个插头,3线UART(TTL电平),5V电源.UART用作ISP下载和以后的串口调试用.
4. 可装4节5号电池的电池盒一个(主板有充电功能,可装普通充电电池节省使用费用,充电时单片机可以被唤醒以控制充电过程).
5.质量最好的万能遥控器一只,控制小车,也可以当作家里的电视遥控器,质量很好(塑料坚固,程序稳定),跟原装的电视遥控器比几乎没任何区别和不方便,甚至比原装的好用,现在我的电视就用这个遥控的.
以上刚好够开发用,没有冗余,也不需要其他设备.
小车视频,因淘宝不允许外链接,请把链接地址拷贝到IE地址栏再打开.
小车爬坡视频文件.
http://player.youku.com/player.php/sid/14268955/v.swf
小车原地转弯视频
http://player.youku.com/player.php/sid/14264115/v.swf
附小车演示程序代码(请朋友们优化):
文件 main.c,其他文件如声音,串口,LCD等未贴出.
#include <stdio.h>
#include <intrins.h>
#include "STC12C5410AD.H"
#include "isd1700.h"
#include "sio.h"
sfr ISP_CUNTR = 0xE7;
sbit LED1 = P1^3;
sbit LED2 = P3^3;
sbit IR_DATA = P3^7;
sbit PWRCON = P3^4;
sbit MOTO_EN_A = P2^0;
sbit MOTO_IN_A1 = P2^1;
sbit MOTO_IN_A2 = P2^2;
sbit MOTO_EN_B = P3^5;
sbit MOTO_IN_B1 = P2^5;
sbit MOTO_IN_B2 = P2^3;
bit power_stat;
static unsigned char code led_mod_table[3][20] = {
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0},
{1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0}
};
unsigned char idata led_mod = 0;
static unsigned char idata led_tick = 0;
static unsigned char idata led_ptr = 0;
unsigned int MOTO_PWM_PERIOD; //电机PWM计数周期
unsigned int MOTO_PWM_STEP; //电机PWM计数周期调节步长
unsigned char MOTO_A_RATIO, MOTO_B_RATIO; //电机PWM占空百分比*100
bit MOTO_A_STATE, MOTO_B_STATE; //电机当前状态
void delay(unsigned long v) {
while (v--) {
}
}
/*
* PCA中断计数,根据位置判断信号区域和定义,位置0表示初始,1代表引导码信号,2表示引导码间隔,
* 3表示第一个bit的信号,4表示第一个bit的间隔,以次类推...
* 更具体见对应的红外线协议.
*/
static unsigned char idata pca_int_count;
static unsigned char data pca_int_total; /* 根据引导头确定总长度 */
static unsigned int idata period; /* 红外信号占或空周期计数 */
static unsigned char idata data_buf[6]; /* 红外线协议数据缓冲区 */
static unsigned int idata ccap0; //PCA0上一次的的计数
static unsigned char idata frame_dog; //红外帧看门狗,限定时间未接收完成清除工作
void time0_isr() interrupt 1
{
TH0 = 0xB8; /* 65536 - XTAL*dur/T6_12/1000000, dur=定时器的周期,以us为单位*/
TL0 = 0x00;
isd_task();
if (led_tick++>= 10) {
led_tick = 0;
if (led_mod_table[led_mod][led_ptr++]) {
LED1 = 0;
LED2 = 0;
} else {
LED1 = 1;
LED2 = 1;
}
led_ptr %= 20;
}
}
void time0_initialize(void)
{
TMOD &= ~0x0F; /* clear timer 0 mode bits */
TMOD |= 0x01; /* put timer 0 into MODE 1 */
TH0 = 0xB8; /* 65536 - XTAL*dur/T6_12/1000000, dur=定时器的周期,以us为单位*/
TL0 = 0x00; /* 10ms */
PT0 = 0; /* 时钟0中断低优先级 */
TR0 = 1;
ET0 = 1;
}
static void wakeup (void) interrupt 2
{
}
static void pca_isr (void) interrupt 6
{
unsigned char i, j;
unsigned int tmp;
if (CCF0) {
CCF0 = 0; //清PCA0中断标志
LED1 = IR_DATA;
LED2 = IR_DATA;
if (!pca_int_count) { //第一次收到信号
if (!IR_DATA) {
ccap0 = CCAP0H * 256 + CCAP0L;
pca_int_count++;
}
} else { //已经收到一些信号
period = CCAP0H * 256 + CCAP0L - ccap0;
ccap0 = CCAP0H * 256 + CCAP0L;
if (pca_int_count == 1) {
if (period < 0x3B00 || period> 0x4400) { //9ms中心0x40cc
pca_int_count = 0;
frame_dog = 0;
} else
pca_int_count++;
} else if (pca_int_count == 2) {
if (period> 0x0d00 && period < 0x1233) { //2.25ms中心0x1033
pca_int_total = 3;
pca_int_count++;
} else if (period> 0x1c00 && period < 0x2466) { //4.5ms中心0x2066
pca_int_total = 67;
pca_int_count++;
} else {
pca_int_count = 0;
frame_dog = 0;
}
} else {
if (IR_DATA) {
if (period> 0x0300 && period < 0x0500) { //0.56ms中心0x0408
if (pca_int_count>= pca_int_total) { //帧接收完毕,下面进行有效性分析.
if (pca_int_total == 67) { //完整信号,含有引导信号,设备码8bit,设备反码8bit,命令字8bit,命令字反码8bit
if ((data_buf[0] ^ data_buf[1] == 0xff) && (data_buf[2] ^ data_buf[3] == 0xff)) {
com_putchar(data_buf[0]);
com_putchar(data_buf[2]);
if (data_buf[0] == 0x40) {
switch (data_buf[2]) {
case 0x5F: //左
MOTO_EN_A = 0;
MOTO_EN_B = 0;
_nop_();
_nop_();
_nop_();
MOTO_IN_A1 = 0;
MOTO_IN_A2 = 1;
MOTO_IN_B1 = 0;
MOTO_IN_B2 = 0;
_nop_();
_nop_();
_nop_();
if (MOTO_A_RATIO < MOTO_B_RATIO) {
MOTO_A_RATIO = MOTO_B_RATIO;
MOTO_B_RATIO = 0;
} else {
MOTO_B_RATIO = 0;
}
MOTO_EN_A = MOTO_A_STATE;
MOTO_EN_B = MOTO_B_STATE;
break;
case 0x5B: //右
MOTO_EN_A = 0;
MOTO_EN_B = 0;
_nop_();
_nop_();
_nop_();
MOTO_IN_A1 = 0;
MOTO_IN_A2 = 0;
MOTO_IN_B1 = 0;
MOTO_IN_B2 = 1;
_nop_();
_nop_();
_nop_();
if (MOTO_B_RATIO < MOTO_A_RATIO) {
MOTO_B_RATIO = MOTO_A_RATIO;
MOTO_A_RATIO = 0;
} else {
MOTO_A_RATIO = 0;
}
MOTO_EN_A = MOTO_A_STATE;
MOTO_EN_B = MOTO_B_STATE;
break;
case 0x5A: //上
MOTO_EN_A = 0;
MOTO_EN_B = 0;
_nop_();
_nop_();
_nop_();
MOTO_IN_A1 = 0;
MOTO_IN_A2 = 1;
MOTO_IN_B1 = 0;
MOTO_IN_B2 = 1;
_nop_();
_nop_();
_nop_();
if (MOTO_B_RATIO < MOTO_A_RATIO) {
MOTO_B_RATIO = MOTO_A_RATIO;
} else {
MOTO_A_RATIO = MOTO_B_RATIO;
}
MOTO_EN_A = MOTO_A_STATE;
MOTO_EN_B = MOTO_B_STATE;
break;
case 0x5E: //下
MOTO_EN_A = 0;
MOTO_EN_B = 0;
_nop_();
_nop_();
_nop_();
MOTO_IN_A1 = 1;
MOTO_IN_A2 = 0;
MOTO_IN_B1 = 1;
MOTO_IN_B2 = 0;
_nop_();
_nop_();
_nop_();
if (MOTO_B_RATIO < MOTO_A_RATIO) {
MOTO_B_RATIO = MOTO_A_RATIO;
} else {
MOTO_A_RATIO = MOTO_B_RATIO;
}
MOTO_EN_A = MOTO_A_STATE;
MOTO_EN_B = MOTO_B_STATE;
break;
case 0x56: //菜单
MOTO_IN_A1 = 0;
MOTO_IN_A2 = 0;
MOTO_IN_B1 = 0;
MOTO_IN_B2 = 0;
break;
case 0x12: //POWER
power_stat = ~power_stat;
break;
case 0x0: //0
play_sound(1);
MOTO_A_RATIO = 100;
MOTO_B_RATIO = 100;
break;
case 0x1: //1
play_sound(2);
break;
case 0x2:
play_sound(3);
break;
case 0x3:
play_sound(4);
break;
case 0x4:
play_sound(5);
break;
case 0x5:
play_sound(6);
break;
case 0x6:
play_sound(7);
break;
case 0x7:
play_sound(8);
break;
case 0x8:
play_sound(9);
break;
case 0x9: //9
play_sound(10);
break;
case 0x1A: //+
play_sound(SOUND_SHOOT);
if (MOTO_A_RATIO < 90)
MOTO_A_RATIO += 10;
if (MOTO_B_RATIO < 90)
MOTO_B_RATIO += 10;
break;
case 0x1E: //-
if (MOTO_A_RATIO> 10)
MOTO_A_RATIO -= 5;
if (MOTO_B_RATIO> 10)
MOTO_B_RATIO -= 5;
break;
case 0x1B: //频道上调
MOTO_PWM_PERIOD = (MOTO_PWM_PERIOD / 100) * 90;
break;
case 0x1F: //频道下调
MOTO_PWM_PERIOD = (MOTO_PWM_PERIOD / 100) * 110;
break;
default:
break;
}
}
}
} else { //重复信号,仅含有引导信号
}
pca_int_count = 0;
frame_dog = 0;
} else {
pca_int_count++;
}
} else {
pca_int_count = 0;
frame_dog = 0;
}
} else {
j = (pca_int_count - 3) / 2;
i = j / 8;
j = j % 8;
if (period> 0x0a00 && period < 0x0e00) { //1.68ms中心0x0c18
// com_putchar(0x01);
data_buf |= (0x01 << j);
pca_int_count++;
} else if (period> 0x0300 && period < 0x0500) { //0.56ms中心0x0408
// com_putchar(0x00);
data_buf &= ~(0x01 << j);
pca_int_count++;
} else {
pca_int_count = 0;
frame_dog = 0;
}
}
}
}
}
if (CCF1) {
CCF1 = 0;
if (!MOTO_B_STATE) {
if (MOTO_B_RATIO <= 10) { //占比小于等于10%都当作0%
CCAP1L = MOTO_PWM_PERIOD % 256;
CCAP1H = MOTO_PWM_PERIOD / 256;
} else {
tmp = MOTO_PWM_PERIOD / 100 * MOTO_B_RATIO;
CCAP1L = tmp % 256;
CCAP1H = tmp / 256;
MOTO_B_STATE = 1;
MOTO_EN_B = 1;
}
} else {
if (MOTO_B_RATIO>= 90) { //占比大于等于90%都当作100%
CCAP1L = MOTO_PWM_PERIOD % 256;
CCAP1H = MOTO_PWM_PERIOD / 256;
} else {
tmp = MOTO_PWM_PERIOD / 100 * (100 - MOTO_B_RATIO);
CCAP1L = tmp % 256;
CCAP1H = tmp / 256;
MOTO_B_STATE = 0;
MOTO_EN_B = 0;
}
}
}
if (CCF2) {
CCF2 = 0;
if (!MOTO_A_STATE) {
if (MOTO_A_RATIO <= 10) { //占比小于等于10%都当作0%
CCAP2L = MOTO_PWM_PERIOD % 256;
CCAP2H = MOTO_PWM_PERIOD / 256;
} else {
tmp = MOTO_PWM_PERIOD / 100 * MOTO_A_RATIO;
  |
|