偶然在b站看到这个项目机械数码管,正好手边有个ESP8266模块还有PCA9685就来做一下。
模型下载地址
目前就搞了一个数字,未来工厂3d打印太贵了
PCA9685
要先设置频率寄存器才能有输出,想设置频率寄存器必须先把MODE1寄存器的SLEEP位置一。
void set_freq(float freq)
{
u16 prescale,oldmode,newmode;
float prescaleval;
unsigned int day_time = 0;
freq *= 0.92;
prescaleval = 25000000;
prescaleval /= 4096; //prescaleval=round(osc_cloc/4096/freq)-1;
prescaleval /= freq;
prescaleval -= 1;
prescale = floor(prescaleval + 0.5);
oldmode = I2C_Read_One_Byte(0x80, PCA9685_MODE1_reg);
newmode = (oldmode&0xEF) | 0x10;
I2C_Write_One_Byte(0x80, PCA9685_MODE1_reg, newmode);
I2C_Write_One_Byte(0x80, PCA9685_PRE_SCALE_reg, prescale);
I2C_Write_One_Byte(0x80, PCA9685_MODE1_reg, oldmode);
delay_ms(2);
I2C_Write_One_Byte(0x80, PCA9685_MODE1_reg, (oldmode | 0xa1));
}
ESP8266
ESP8266测试
先连接esp8266到电脑,用串口助手发送命令检测模块的功能
#测试模块能否正常工作
AT
#设置模块为sta模式
AT+CWMODE=1
#重启试生效
AT+RST
#连接WiFi
AT+CWJAP="热点名字","密码"
#设置单路模式
AT+CIPMUX=0
时间API
我使用的是淘宝免费的api
#TCP连接
AT+CIPSTART="TCP","api.m.taobao.com",80
#发送71个字符
AT+CIPSEND=71
出现“>”可以发送指令
输入GET命令,获取时间:
GET http://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp
#透传模式开
AT+CIPMODE=1
#发送数据
AT+CIPSEND
esp8266退出透传模式重新使能AT命令发送“+++”(注意取消串口助手的发送新行)。实际连接单片机使用时出现不断重启的问题,检查后发现应该时模块的供电不够导致的。
串口控制ESP8266
实际使用时发现还是不进入透传模式更方便
char tcp_con[] = "AT+CIPSTART=\"TCP\",\"api.m.taobao.com\",80\r\n";
char send_comm[] = "AT+CIPSEND=71\r\n";
char get_comm[] = "GET http://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp\r\n";
esp8266_init_time();
while(time_flag == NON_OK);
time_flag = NON_OK;
void esp8266_init_time()
{
esp8266_send(tcp_con);
delay_ms(100);
esp8266_send(send_comm);
delay_ms(100);
esp8266_send(get_comm);
delay_ms(100);
}
void esp8266_send(char* str)
{
uart4_send_str(str);
}
串口4接收返回的时间戳
每次串口接收到新行“\r\n”,接收缓冲区就从头开始接收。根据实际得到的淘宝网返回的字符串格式,发现字符串开头是“+IPD”结尾是“CLOSED”,把这个当作帧头帧尾查找,确定unix时间戳字符所在的位置并将其转化成数值。
u8 day_hour = 0;
u8 day_min = 0;
u8 day_sec = 0;
void UART4_IRQHandler()
{
u8 res;
static int index = 0;
u8 counter = 0;
unsigned int multi = 1;
unsigned int day_time = 0;
if(USART_GetITStatus(UART4, USART_IT_RXNE) != RESET)
{
res = USART_ReceiveData(UART4);
rxbuff[index] = res;
if((rxbuff[index] == '\n') && (rxbuff[index-1] == '\r'))
{
if((rxbuff[index-2] == 'D')&&(rxbuff[index-3] == 'E')&&(rxbuff[index-4] == 'S')&&(rxbuff[index-5] == 'O')&&(rxbuff[index-6] == 'L')&&(rxbuff[index-7] == 'C')&&(rxbuff[0] == '+'))
{
unix_time = 0;
multi = 1;
for(counter = 0;counter < 10;counter++)
{
unix_time += (rxbuff[111-counter] - 0x30) * multi;
multi = multi * 10;
}
day_time = unix_time % 86400;
day_hour = day_time / 3600 + 8;
day_min = (day_time % 3600) / 60;
day_sec = (day_time % 3600) % 60;
//day_hour = day_hour + 8;
//printf("%d:%2d:%2d\r\n", day_hour, day_min, day_sec);
time_flag = OK;
}
index = 0;
}
else
{
index++;
}
}
}
stm32f1串口发送
使用串口发送字符串时,出现了第一个字符发送不出来的情况。
置零sr的tc位:
UART4->SR |= 0xBF;
或者读取一下SR寄存器:
(void)UART4->SR;
定时器每秒钟刷新时间每小时对时一次
#define CHECK_DURATION 3600
void TIM2_IRQHandler(void) //TIM3??
{
static u8 flag = 0;
static unsigned int counter = 0;
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) //??TIM3????????
{
if(counter == CHECK_DURATION)
{
esp8266_init();
//while(time_flag == NON_OK);
time_flag = NON_OK;
counter = 0;
printf("TIME_SYNC\r\n");
}
else
{
if(day_sec == 59)
{
day_sec = 0;
if(day_min == 59)
{
day_min = 0;
if(day_hour == 23)
{
day_hour = 0;
}
else
{
day_hour++;
}
}
else
{
day_min++;
}
}
else
{
day_sec++;
}
counter++;
}
if(flag == 0)
{
GPIO_ResetBits(GPIOG,GPIO_Pin_13);
flag = ~flag;
}
else
{
GPIO_SetBits(GPIOG,GPIO_Pin_13);
flag = ~flag;
}
printf("%d:%2d:%2d\r\n", day_hour, day_min, day_sec);
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
如下图可以得到正确的时间:
字符编码
// A B C D E F G
char number[] = {0xcd, 0x00, 0xcd, 0x00, 0x99, 0x01, 0xcd, 0x00, 0x99, 0x01, 0xcd, 0x00, 0xcd, 0x00, //0
0x99, 0x01, 0x99, 0x01, 0x99, 0x01, 0xcd, 0x00, 0xcd, 0x00, 0xcd, 0x00, 0x99, 0x01, //1
0xcd, 0x00, 0x99, 0x01, 0x99, 0x01, 0x99, 0x01, 0x99, 0x01, 0x99, 0x01, 0xcd, 0x00, //2
0xcd, 0x00, 0x99, 0x01, 0x99, 0x01, 0x99, 0x01, 0xcd, 0x00, 0xcd, 0x00, 0xcd, 0x00, //3
0x99, 0x01, 0xcd, 0x00, 0x99, 0x01, 0x99, 0x01, 0xcd, 0x00, 0xcd, 0x00, 0x99, 0x01, //4
0xcd, 0x00, 0xcd, 0x00, 0xcd, 0x00, 0x99, 0x01, 0xcd, 0x00, 0xcd, 0x00, 0xcd, 0x00, //5
0xcd, 0x00, 0xcd, 0x00, 0xcd, 0x00, 0x99, 0x01, 0x99, 0x01, 0xcd, 0x00, 0xcd, 0x00, //6
0xcd, 0x00, 0x99, 0x01, 0x99, 0x01, 0xcd, 0x00, 0xcd, 0x00, 0xcd, 0x00, 0x99, 0x01, //7
0xcd, 0x00, 0xcd, 0x00, 0x99, 0x01, 0x99, 0x01, 0x99, 0x01, 0xcd, 0x00, 0xcd, 0x00, //8
0xcd, 0x00, 0xcd, 0x00, 0x99, 0x01, 0x99, 0x01, 0xcd, 0x00, 0xcd, 0x00, 0xcd, 0x00}; //9
//在定时器中断当中调用
void set_num(char num)
{
//A
I2C_Write_One_Byte(0x80, PCA9685_CH0_ON_L_reg, 0x00);
I2C_Write_One_Byte(0x80, PCA9685_CH0_ON_H_reg, 0x00);
I2C_Write_One_Byte(0x80, PCA9685_CH0_OFF_L_reg, number[num*14]);
I2C_Write_One_Byte(0x80, PCA9685_CH0_OFF_H_reg, number[num*14+1]);//199-0 cd-1
//delay_ms(500);
//B
I2C_Write_One_Byte(0x80, PCA9685_CH1_ON_L_reg, 0x00);
I2C_Write_One_Byte(0x80, PCA9685_CH1_ON_H_reg, 0x00);
I2C_Write_One_Byte(0x80, PCA9685_CH1_OFF_L_reg, number[num*14+2]);
I2C_Write_One_Byte(0x80, PCA9685_CH1_OFF_H_reg, number[num*14+3]);//199-0 cd-1
//delay_ms(500);
//C
I2C_Write_One_Byte(0x80, PCA9685_CH2_ON_L_reg, 0x00);
I2C_Write_One_Byte(0x80, PCA9685_CH2_ON_H_reg, 0x00);
I2C_Write_One_Byte(0x80, PCA9685_CH2_OFF_L_reg, number[num*14+4]);
I2C_Write_One_Byte(0x80, PCA9685_CH2_OFF_H_reg, number[num*14+5]);//199-0 cd-1
//delay_ms(500);
//D
I2C_Write_One_Byte(0x80, PCA9685_CH3_ON_L_reg, 0x00);
I2C_Write_One_Byte(0x80, PCA9685_CH3_ON_H_reg, 0x00);
I2C_Write_One_Byte(0x80, PCA9685_CH3_OFF_L_reg, number[num*14+6]);
I2C_Write_One_Byte(0x80, PCA9685_CH3_OFF_H_reg, number[num*14+7]);//199-0 cd-1
//delay_ms(500);
//E
I2C_Write_One_Byte(0x80, PCA9685_CH4_ON_L_reg, 0x00);
I2C_Write_One_Byte(0x80, PCA9685_CH4_ON_H_reg, 0x00);
I2C_Write_One_Byte(0x80, PCA9685_CH4_OFF_L_reg, number[num*14+8]);
I2C_Write_One_Byte(0x80, PCA9685_CH4_OFF_H_reg, number[num*14+9]);//199-0 cd-1
//delay_ms(500);
//F
I2C_Write_One_Byte(0x80, PCA9685_CH5_ON_L_reg, 0x00);
I2C_Write_One_Byte(0x80, PCA9685_CH5_ON_H_reg, 0x00);
I2C_Write_One_Byte(0x80, PCA9685_CH5_OFF_L_reg, number[num*14+10]);
I2C_Write_One_Byte(0x80, PCA9685_CH5_OFF_H_reg, number[num*14+11]);//199-0 cd-1
//delay_ms(500);
//G
I2C_Write_One_Byte(0x80, PCA9685_CH6_ON_L_reg, 0x00);
I2C_Write_One_Byte(0x80, PCA9685_CH6_ON_H_reg, 0x00);
I2C_Write_One_Byte(0x80, PCA9685_CH6_OFF_L_reg, number[num*14+12]);
I2C_Write_One_Byte(0x80, PCA9685_CH6_OFF_H_reg, number[num*14+13]);//199-0 cd-1
}