目录
定时器介绍:
中断寄存器介绍:
CPU能响应定时器0中断的条件:需要配置IE寄存器的bit1: ET0 bit7:EA
测试数据通过串口发送到上位机
- //main.c
- #include "motor.h"
- #include "delay.h"
- #include "uart.h"
- #include "reg52.h"
- #include "time.h"
- #include "stdio.h"
-
- sbit speedIO = P3^2;//外部中断0
- unsigned int speedCnt = 0; //统计格子,脉冲次数
- extern unsigned int speed;//速度
- extern char signal; //主程序发速度数据的通知
- char speedMes[24]; //主程序发送速度数据的字符串缓冲区
-
- void Ex0Init()
- {
- EX0 = 1;//允许中断
- //EA = 1;在串口初始化函数中已经打开了总中断
- IT0 = 1;//外部中断的下降沿触发
- }
-
- void main()
- {
- Time0Init();//定时器0初始化
- UartInit();//串口相关初始化
- //外部中断初始化
- Ex0Init();
-
- while(1){
- if(signal){//定时器1s到点,把signal置一,主程序发送速度
- sprintf(speedMes,"speed:%d cm/s",speed);//串口数据的字符串拼装,speed是格子,每个格子1cm
- SendString(speedMes);//速度发出去
- signal = 0;//清0speed,下次由定时器1s后的中断处理中再置一
- }
- }
- }
-
- void speedHandler() interrupt 0 //外部中断处理函数
- {
- speedCnt++;//码盘转动了一个格子
- }
-
- //uart.c
- #include "reg52.h"
- #include "motor.h"
- #include "string.h"
- sbit D5 = P3^7;
- #define SIZE 12
-
- sfr AUXR = 0x8E;
- char buffer[SIZE];
-
- void UartInit(void) //9600bps@11.0592MHz
- {
- AUXR = 0x01;
- SCON = 0x50; //配置串口工作方式1,REN使能接收
- TMOD &= 0x0F;
- TMOD |= 0x20;//定时器1工作方式位8位自动重装
-
- TH1 = 0xFD;
- TL1 = 0xFD;//9600波特率的初值
- TR1 = 1;//启动定时器
-
- EA = 1;//开启总中断
- ES = 1;//开启串口中断
- }
-
-
- void SendByte(char mydata)
- {
- SBUF = mydata;
- while(!TI);
- TI = 0;
- }
-
- void SendString(char *str)
- {
- while(*str != '\0'){
- SendByte(*str);
- str++;
- }
- }
-
-
- //M1qian M2 hou M3 zuo M4 you
- void Uart_Handler() interrupt 4
- {
- static int i = 0;//静态变量,被初始化一次
- char tmp;
-
- if(RI)//中断处理函数中,对于接收中断的响应
- {
- RI = 0;//清除接收中断标志位
- tmp = SBUF;
- if(tmp == 'M'){
- i = 0;
- }
- buffer[i++] = tmp;
-
- //灯控指令
- if(buffer[0] == 'M'){
- switch(buffer[1]){
- case '1':
- goForward();
- break;
- case '2':
- goBack();
- break;
- case '3':
- goLeft();
- break;
- case '4':
- goRight();
- break;
- default:
- stop();
- break;
- }
- }
-
- if(i == 12) {
- memset(buffer, '\0', SIZE);
- i = 0;
- }
- }
-
- }
-
- //motor.c
- #include "reg52.h"
-
- sbit RightCon1A = P3^7;
- sbit RightCon1B = P3^3;
-
- sbit LeftCon1A = P3^4;
- sbit LeftCon1B = P3^5;
-
- void goForward()
- {
- LeftCon1A = 0;
- LeftCon1B = 1;
-
- RightCon1A = 0;
- RightCon1B = 1;
- }
-
- void goRight()
- {
- LeftCon1A = 0;
- LeftCon1B = 1;
-
- RightCon1A = 0;
- RightCon1B = 0;
- }
-
-
- void goLeft()
- {
- LeftCon1A = 0;
- LeftCon1B = 0;
-
- RightCon1A = 0;
- RightCon1B = 1;
- }
-
- void goBack()
- {
- LeftCon1A = 1;
- LeftCon1B = 0;
-
- RightCon1A = 1;
- RightCon1B = 0;
- }
-
- void stop()
- {
- LeftCon1A = 0;
- LeftCon1B = 0;
-
- RightCon1A = 0;
- RightCon1B = 0;
- }
-
- //time.c
- #include "motor.h"
- #include "reg52.h"
-
- extern unsigned int speedCnt;
- unsigned int speed;
- char signal = 0;
- unsigned int cnt = 0;
-
- void Time0Init()
- {
- //1. 配置定时器0工作模式位16位计时
- TMOD = 0x01;
- //2. 给初值,定一个0.5出来
- TL0=0x33;
- TH0=0xFE;
- //3. 开始计时
- TR0 = 1;
- TF0 = 0;
- //4. 打开定时器0中断
- ET0 = 1;
- //5. 打开总中断EA
- EA = 1;
- }
-
- void Time0Handler() interrupt 1
- {
- cnt++; //统计爆表的次数. cnt=1的时候,报表了1
- //重新给初值
- TL0=0x33;
- TH0=0xFE;
-
- if(cnt == 2000){//爆表2000次,经过了1s
- signal = 1;
- cnt = 0; //当100次表示1s,重新让cnt从0开始,计算下一次的1s
- //计算小车的速度,也就是拿到speedCnt的值
- speed = speedCnt;
- speedCnt = 0;//1秒后拿到speedCnt个格子,就能算出这1s的速度,格子清零
- }
-
- }
使用oled模块,oled写命令
写命令/数据的代码分析:
最终小车代码整合:
- //main.c
- #include "reg52.h"
- #include "intrins.h"
- #include "Oled.h"
-
- void main()
- {
- //1. OLED初始化
- Oled_Init();
- Oled_Clear();
- Oled_Show_Str(2,2,"speed:35cm/s");
-
- while(1);
- }
-
- //oled.c
- #include "reg52.h"
- #include "intrins.h"
- #include "Oledfont.h"
-
-
- sbit scl = P1^2;
- sbit sda = P1^3;
-
- void IIC_Start()
- {
- scl = 0;
- sda = 1;
- scl = 1;
- _nop_();
- sda = 0;
- _nop_();
- }
-
- void IIC_Stop()
- {
- scl = 0;
- sda = 0;
- scl = 1;
- _nop_();
- sda = 1;
- _nop_();
- }
-
- char IIC_ACK()
- {
- char flag;
- sda = 1;//就在时钟脉冲9期间释放数据线
- _nop_();
- scl = 1;
- _nop_();
- flag = sda;
- _nop_();
- scl = 0;
- _nop_();
-
- return flag;
- }
-
- void IIC_Send_Byte(char dataSend)
- {
- int i;
-
- for(i = 0;i<8;i++){
- scl = 0;//scl拉低,让sda做好数据准备
- sda = dataSend & 0x80;//1000 0000获得dataSend的最高位,给sda
- _nop_();//发送数据建立时间
- scl = 1;//scl拉高开始发送
- _nop_();//数据发送时间
- scl = 0;//发送完毕拉低
- _nop_();//
- dataSend = dataSend << 1;
- }
- }
-
- void Oled_Write_Cmd(char dataCmd)
- {
- // 1. start()
- IIC_Start();
- //
- // 2. 写入从机地址 b0111 1000 0x78
- IIC_Send_Byte(0x78);
- // 3. ACK
- IIC_ACK();
- // 4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
- IIC_Send_Byte(0x00);
- // 5. ACK
- IIC_ACK();
- //6. 写入指令/数据
- IIC_Send_Byte(dataCmd);
- //7. ACK
- IIC_ACK();
- //8. STOP
- IIC_Stop();
- }
-
- void Oled_Write_Data(char dataData)
- {
- // 1. start()
- IIC_Start();
- //
- // 2. 写入从机地址 b0111 1000 0x78
- IIC_Send_Byte(0x78);
- // 3. ACK
- IIC_ACK();
- // 4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
- IIC_Send_Byte(0x40);
- // 5. ACK
- IIC_ACK();
- ///6. 写入指令/数据
- IIC_Send_Byte(dataData);
- //7. ACK
- IIC_ACK();
- //8. STOP
- IIC_Stop();
- }
-
-
- void Oled_Init(void){
- Oled_Write_Cmd(0xAE);//--display off
- Oled_Write_Cmd(0x00);//---set low column address
- Oled_Write_Cmd(0x10);//---set high column address
- Oled_Write_Cmd(0x40);//--set start line address
- Oled_Write_Cmd(0xB0);//--set page address
- Oled_Write_Cmd(0x81); // contract control
- Oled_Write_Cmd(0xFF);//--128
- Oled_Write_Cmd(0xA1);//set segment remap
- Oled_Write_Cmd(0xA6);//--normal / reverse
- Oled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
- Oled_Write_Cmd(0x3F);//--1/32 duty
- Oled_Write_Cmd(0xC8);//Com scan direction
- Oled_Write_Cmd(0xD3);//-set display offset
- Oled_Write_Cmd(0x00);//
-
- Oled_Write_Cmd(0xD5);//set osc division
- Oled_Write_Cmd(0x80);//
-
- Oled_Write_Cmd(0xD8);//set area color mode off
- Oled_Write_Cmd(0x05);//
-
- Oled_Write_Cmd(0xD9);//Set Pre-Charge Period
- Oled_Write_Cmd(0xF1);//
-
- Oled_Write_Cmd(0xDA);//set com pin configuartion
- Oled_Write_Cmd(0x12);//
-
- Oled_Write_Cmd(0xDB);//set Vcomh
- Oled_Write_Cmd(0x30);//
-
- Oled_Write_Cmd(0x8D);//set charge pump enable
- Oled_Write_Cmd(0x14);//
-
- Oled_Write_Cmd(0xAF);//--turn on oled panel
- }
-
- void Oled_Clear()
- {
- unsigned char i,j; //-128 --- 127
-
- for(i=0;i<8;i++){
- Oled_Write_Cmd(0xB0 + i);//page0--page7
- //每个page从0列
- Oled_Write_Cmd(0x00);
- Oled_Write_Cmd(0x10);
- //0到127列,依次写入0,每写入数据,列地址自动偏移
- for(j = 0;j<128;j++){
- Oled_Write_Data(0);
- }
- }
- }
-
- void Oled_Show_Char(char row,char col,char oledChar){ //row*2-2
- unsigned int i;
- Oled_Write_Cmd(0xb0+(row*2-2)); //page 0
- Oled_Write_Cmd(0x00+(col&0x0f)); //low
- Oled_Write_Cmd(0x10+(col>>4)); //high
- for(i=((oledChar-32)*16);i<((oledChar-32)*16+8);i++){
- Oled_Write_Data(F8X16[i]); //写数据oledTable1
- }
-
- Oled_Write_Cmd(0xb0+(row*2-1)); //page 1
- Oled_Write_Cmd(0x00+(col&0x0f)); //low
- Oled_Write_Cmd(0x10+(col>>4)); //high
- for(i=((oledChar-32)*16+8);i<((oledChar-32)*16+8+8);i++){
- Oled_Write_Data(F8X16[i]); //写数据oledTable1
- }
- }
-
-
- /******************************************************************************/
- // 函数名称:Oled_Show_Char
- // 输入参数:oledChar
- // 输出参数:无
- // 函数功能:OLED显示单个字符
- /******************************************************************************/
- void Oled_Show_Str(char row,char col,char *str){
- while(*str!=0){
- Oled_Show_Char(row,col,*str);
- str++;
- col += 8;
- }
- }