一、第一印象,价格绝对便宜,5毛左右,带在线调试,内部高速晶振,秒杀STC的51,看程序ROM的位数跟十年前用的PIC很相像,猜测是MICROCHIP授权的指令集。
最小SOP8封装,所以硬件资源有点缺乏、2个定时器、有PWM功能,带看门狗,只能应用于家电类、玩具类型产品,看在价格上也只能接受。
二、开发环境,一个仿keil C51的界面,当然Keil C51也是仿VC6的
不过比较好的使用GCC的编译器,没有使用那个难用的PIC编译器
语法上与普通的C编译器差别不大,熟悉一下硬件就硬件上手
三、例程代码 内部EEPROM读写
unsigned char EEPROMread(unsigned char EEAddr)
{
unsigned char ReEEPROMread;
EEADR = EEAddr;
RD = 1;
ReEEPROMread = EEDAT; // EEPROM的读数据 ReEEPROMread = EEDATA;
return ReEEPROMread;
}
void EEPROMwrite(unsigned char EEAddr, unsigned char Data)
{
GIE = 0; // 写数据必须关闭中断
while (GIE)
; // 等待GIE为0
EEADR = EEAddr; // EEPROM的地址
EEDAT = Data; // EEPROM的写数据 EEDATA = Data;
EEIF = 0;
EECON1 |= 0x34; // 置位WREN1,WREN2,WREN3三个变量.
WR = 1; // 置位WR启动编程
while (WR)
; // 等待EE写入完成
GIE = 1;
}
四、中断处理,只有一个中断向量,需要在程序中判断相应的标记处理中断
void interrupt ISR(void)
{
// PA2 INT (KEY)
if (INTE && INTF)
{
INTF = 0; // 清标志位
}
// PA 电平INT
if (PAIE && PAIF)
{
PAIF = 0; //清PAIF标志位
}
// TIM0 1ms
if (T0IE && T0IF)
{
T0IF = 0;
LED_Control();
ms_s_Count++;
if (ms_s_Count == 1000)
{
ms_s_Count = 0;
Scan_Info_Flag = 1;
if (Sleep_Count_Down > 0)
{
// 循环开启升压
if (Boost_Switch)
{
Restart_Boost_Count++;
if (Restart_Boost_Count == RESTART_BOOST_TIME_SET)
{
Restart_Boost_Count = 0;
Restart_Boost_Flag = 1;
}
}
Sleep_Count_Down--;
if (Sleep_Count_Down == 0)
{
Sleep_Flag = 1;
}
}
}
}
// TIM2 50us
if (TMR2IE && TMR2IF)
{
TMR2IF = 0;
if (Pack_Data_Rx_Level_Time_Count_Flag == 1)
{
Pack_Data_Rx_Level_Time_Count++; // 电平维持时间计数
}
if (_50us_To_500us_Count < 10)
{
_50us_To_500us_Count++;
if (_50us_To_500us_Count == 10)
{
_50us_To_500us_Count = 0;
Pack_Data_TX_Process();
}
}
}
}
五、使用总结
小芯片硬件通讯就不要想了,基本只有IO模拟,反正从51过来的工程师,也会习惯的,程序结构也只有大循环或者中断的前后台模式,小产品程序量也不会大,一些基本功能就够。再放个I2C模拟程序
void IIC_Start(void)
{
I2C_SDA_OUT; // SDA线输出
I2C_SDA = 1;
I2C_SCK = 1;
DelayUs(2);
I2C_SDA = 0; //开始:当SCL为高时,SDA由高变低
DelayUs(2);
I2C_SCK = 0; //钳住I2C总线,准备发送或接收数据
DelayUs(2);
}
void IIC_Stop(void)
{
I2C_SDA_OUT; // SDA线输出
I2C_SCK = 0;
I2C_SDA = 0; //停止:当SCL为高时,SDA由低变高
DelayUs(2);
I2C_SCK = 1;
DelayUs(2);
I2C_SDA = 1; //发送I2C总线结束信号
DelayUs(2);
}
unsigned char IIC_Wait_Ack(void)
{
unsigned char ucErrTime = 0;
I2C_SDA_IN; // SDA设置为输入
I2C_SDA = 1;
DelayUs(1);
I2C_SCK = 1;
DelayUs(1);
while (I2C_SDA)
{
ucErrTime++;
if (ucErrTime > 250) //等待超时
{
IIC_Stop();
return 1;
}
}
I2C_SCK = 0; //时钟输出0
return 0;
}
void IIC_Ack(void)
{
I2C_SCK = 0;
I2C_SDA_OUT; // SDA线输出
I2C_SDA = 0;
DelayUs(1);
I2C_SCK = 1;
DelayUs(1);
I2C_SCK = 0;
}
void IIC_NAck(void)
{
I2C_SCK = 0;
I2C_SDA_OUT; // SDA线输出
I2C_SDA = 1;
DelayUs(1);
I2C_SCK = 1;
DelayUs(1);
I2C_SCK = 0;
}
void IIC_Send_Byte(unsigned char txd)
{
unsigned char t;
I2C_SDA_OUT; // SDA线输出
I2C_SCK = 0; //拉低时钟开始数据传输
for (t = 0; t < 8; t++)
{
if (txd & 0x80)
I2C_SDA = 1;
else
I2C_SDA = 0;
txd <<= 1;
DelayUs(1);
I2C_SCK = 1;
DelayUs(1);
I2C_SCK = 0;
DelayUs(1);
}
}
unsigned char IIC_Read_Byte(void)
{
unsigned char i, receive = 0;
I2C_SDA_IN; // SDA设置为输入
for (i = 0; i < 8; i++)
{
I2C_SCK = 0;
DelayUs(1);
I2C_SCK = 1;
receive <<= 1;
if (I2C_SDA)
receive++;
DelayUs(1);
}
IIC_NAck(); //发送nACK
return receive;
}
unsigned char IIC_READ(unsigned char address)
{
unsigned char iicdata = 0;
IIC_READ_Begin:
IIC_Start();
// IIC_Send_Byte(0xa0);
IIC_Send_Byte(0x78);
// IIC_Send_Byte(0x3C);
if (IIC_Wait_Ack())
goto IIC_READ_Begin;
IIC_Send_Byte(address); //填要读的数据地址
if (IIC_Wait_Ack())
goto IIC_READ_Begin;
IIC_Start();
// IIC_Send_Byte(0xa1);
IIC_Send_Byte(0x79);
// IIC_Send_Byte(0x3D);
if (IIC_Wait_Ack())
goto IIC_READ_Begin;
iicdata = IIC_Read_Byte();
IIC_Stop();
return iicdata;
}
void IIC_WRITE(unsigned char address, unsigned char data)
{
IIC_WRITE_Begin:
IIC_Start();
// IIC_Send_Byte(0xa0);
IIC_Send_Byte(0x78);
// IIC_Send_Byte(0x3C);
if (IIC_Wait_Ack())
goto IIC_WRITE_Begin;
IIC_Send_Byte(address);
if (IIC_Wait_Ack())
goto IIC_WRITE_Begin;
IIC_Send_Byte(data);
if (IIC_Wait_Ack())
goto IIC_WRITE_Begin;
IIC_Stop();
}
// I2C CODE END