完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
项目分析
#define n_MBI5043_1_stm8 8 //一根模条有一个stm8带载8个LED驱动芯片 #define LEDs 40 //1个stm8驱动了40个灯 #define Colors 3 //每个灯有3个led灯组成 #define STMs 3 //3个stm8通过uart级联实现 本程序实现(1)uart Tx线中断恢复后能正常显示(2)只需修改主模条程序,来实现升级 灵活的模块拼接(不用刻意培训安装人员): 主从自主判断,常用的方法就是上电检测,确认主从关系 容错率要高: 从设备一段时间接收不到数据,重新分配主从。这就用到看门狗了。 预先考虑项目升级: 升级的时候要尽量少的改动,只更改主单片机的程序,从模块不用修改,就能实现升级。这样要显示的内容只能由主设备发给从设备 代码实现 stm8控制MBI5043的文章基础上进一步作业,只需要实现多个stm8通过UART实现通信的功能就可以了 外设的使用 记得初始化三部曲----时钟,引脚,外设,用到了新的外设,对应引脚和时钟也记得初始化 UART外设的初始化和发送模块先写好,以后就可以直接调用了 类似之前使用SPI外设的方法,查阅datasheet就可以了。 #include “STM8S103F.h” void uart1_init(void) { UART1_CR1=0x00; UART1_CR3=0x00; UART1_CR2=0x00; UART1_BRR2=0x0b; UART1_BRR1=0x08; //波特率9600 UART1_SR &= ~0x20; UART1_CR2=0x2c; //允许发送和接收 } void uart1_send(unsigned char c) { while(!(UART1_SR&0x80)); UART1_DR = c; } 用到了看门狗外设 #include “STM8S103F.h” void IWDG_Init(void) //配置并启动看门狗 { IWDG_KR = 0xcc;//启动独立看门狗 IWDG_KR = 0x55;//写入解锁 IWDG_PR = 0x06;//256分频 IWDG_RLR = 0xff;//设置重载寄存器 IWDG_KR = 0xaa;//锁定并刷新 } void IWDG_Feed(void)//喂狗 { IWDG_KR = 0xaa; } 用到了uart接收中断 --------------------------------开总中断-------------------------- _asm(“rim”); ---------------------根据datasheet编写stm8_interrupt_vector------- /* BASIC INTERRUPT VECTOR TABLE FOR STM8 devices * Copyright (c) 2007 STMicroelectronics */ #include “func.h” #include “public.h” #include “STM8S103F.h” #include “string.h” typedef void @far (*interrupt_handler_t)(void); struct interrupt_vector { unsigned char interrupt_instruction; interrupt_handler_t interrupt_handler; }; @far @interrupt void NonHandledInterrupt (void) { /* in order to detect unexpected events during development, it is recommended to set a breakpoint on the following instruction */ return; } extern void _stext(); /* startup routine */ struct interrupt_vector const _vectab[] = { {0x82, (interrupt_handler_t)_stext}, /* reset */ {0x82, NonHandledInterrupt}, /* trap */ {0x82, NonHandledInterrupt}, /* irq0 */ {0x82, NonHandledInterrupt}, /* irq1 */ {0x82, NonHandledInterrupt}, /* irq2 */ {0x82, NonHandledInterrupt}, /* irq3 */ {0x82, NonHandledInterrupt}, /* irq4 */ {0x82, NonHandledInterrupt}, /* irq5 */ {0x82, NonHandledInterrupt}, /* irq6 */ {0x82, NonHandledInterrupt}, /* irq7 */ {0x82, NonHandledInterrupt}, /* irq8 */ {0x82, NonHandledInterrupt}, /* irq9 */ {0x82, NonHandledInterrupt}, /* irq10 */ {0x82, NonHandledInterrupt}, /* irq11 */ {0x82, NonHandledInterrupt}, /* irq12 */ {0x82, NonHandledInterrupt}, /* irq13 */ {0x82, NonHandledInterrupt}, /* irq14 */ {0x82, NonHandledInterrupt}, /* irq15 */ {0x82, NonHandledInterrupt}, /* irq16 */ {0x82, NonHandledInterrupt}, /* irq17 */ {0x82, UART1_Recv_IRQHandler}, /* irq18 */ {0x82, NonHandledInterrupt}, /* irq19 */ {0x82, NonHandledInterrupt}, /* irq20 */ {0x82, NonHandledInterrupt}, /* irq21 */ {0x82, NonHandledInterrupt}, /* irq22 */ {0x82, NonHandledInterrupt}, /* irq23 */ {0x82, NonHandledInterrupt}, /* irq24 */ {0x82, NonHandledInterrupt}, /* irq25 */ {0x82, NonHandledInterrupt}, /* irq26 */ {0x82, NonHandledInterrupt}, /* irq27 */ {0x82, NonHandledInterrupt}, /* irq28 */ {0x82, NonHandledInterrupt}, /* irq29 */ }; 写main函数 main函数是框架,然后往里面填充程序 main() { //初始化 oclk_init(); //时钟初始化肯定得有 port_init(); //引脚初始化肯定得有 spi_init(); //用到了SPI,所以也要初始化 uart1_init(); TIM4_init(); //有用到TIM4定时器做延时,所以也要初始化 //上电检测,确定主从关系 addr = Start_AddrChosed(); //addr是全局变量,其他地方定义了 //然后就是逻辑实现函数 all_effects(); } 3.上电检测函数–Start_AddrChosed() #include “STM8S103F.h” #include “func.h” //包含了delay(),uart1_send()等函数 unsigned char Start_AddrChosed(void) { unsigned char addr_start=0; delay(80); //wait 80ms uart1_send(111); //一起发数据 delay(10); if(UART1_SR&0x20) //读数据寄存器非空,说明不是首 { addr_start = 9; //首stm8_addr_start仍=0 UART1_SR &= ~0x20; } return addr_start; } 重头戏–all_effects() 先搭建框架 #include “STM8S103F.h” #include “string.h” #include “func.h” #include “function.h” #include “display.h” #include “public.h” void all_effects(void) { IWDG_Init(); //看门狗启动 _asm(“rim”); //打开总中断 while(1) { if(addr==0) { //主设备要做的事情 } else { //从设备要做的事情 } } } 2.主设备 主设备要做的事情 就是 (0)生成3个灯条要显示的数据(1)通过uart下发显示内容;(2)显示自己的数据;(3)延时,根据实现效果而定;(4)看门狗主要是为从设备准备的,主设备顺带加上了。 以最简单的流行效果举例 void uart_disp_delay_IDWG(unsigned char dis_buf_0[],unsigned char dis_buf_1[],unsigned char dis_buf_2[],unsigned long ms) { frame_format_gen(dis_buf_1,dis_buf_2); display(dis_buf_0); delay(ms); //TIM4实现延时功能 IWDG_Feed(); //1s喂一次狗别忘 } ---------------------主设备要做的事情----------------------- for(i=0;i《LEDs*STMs;i++) //next 帧 { memset(dis_buf_n,0,STMs*Colors*LEDs); for(n=0;n《8;n++) //一帧 { dis_buf_n[(n+i)*Colors+1]=11*(8-n); } uart_disp_delay_IDWG(dis_buf_n, dis_buf_n+LEDs*Colors, dis_buf_n+2*LEDs*Colors, 1); } 关于 frame_format_gen() 函数: uart本身就是一个协议,它定义了“单词”的表示方式;本文要发送多组数据,每组数据包含多个“单词”,每个stm8只想截取他自己的部分,就像“断句”一样,一个“句子”开头和结尾加上标识符,进而在“单词”外组成了一个新协议“句子”。 本人定义的句子格式如下: void frame_format_gen(unsigned char dis_buf_1[],unsigned char dis_buf_2[]) //一次点亮,三根模条的(3根*3个颜色*40个灯)360个字节数据 { unsigned char j; while(!(UART1_SR&0x80)); UART1_CR2 |=0x01; //send break Identifier; delay(1); for(j=0;j《Colors*LEDs;j++) //data uart1_send(*(dis_buf_1 +j)); for(j=0;j《Colors*LEDs;j++) //data uart1_send(*(dis_buf_2 +j)); while(!(UART1_SR&0x80)); UART1_CR2 |=0x01; //send break Identifier; delay(1); } send break Identifier后一定要delay uart发送break标识符的时候,硬件并不置位UART1_SR的第8位,导致刚开始发break。数据就开始发了,导致一部分数据被break覆盖掉了。血的教训 从设备 从设备识别到开头并转发break标识符后,接收ColorsLEDs个数据,然后将后面的数据都转发给下一个设备包括结束的break标识符。* ------------------ all_effects()--------------------------- if(data_done_flag) { data_done_flag=0; display(dis_buf_uart1); } ------------------ stm8_interrupt_vector()--------------------------- unsigned char ch,j,break_flag=0; @far @interrupt void UART1_Recv_IRQHandler (void) { if(UART1_SR&0x02) { if(break_flag==0) { addr=1; j=0; break_flag=1; data_done_flag=0; UART1_CR2 |=0x01; //send break Identifier; ch=UART1_DR; IWDG_Feed(); return; } else if(break_flag==2) { break_flag=0; j=0; data_done_flag=1; UART1_CR2 |=0x01; //send break Identifier; ch=UART1_DR; IWDG_Feed(); return; } } if(j《120) //store data then display { break_flag=2; dis_buf_uart1[j]=UART1_DR; j++; return; } else { ch=UART1_DR; uart1_send(ch); //send data to next return; } } 4.利用flash实现横幅滚动 注意事项 1.延迟400ms。//因为SWIM下载程序的同时开始运行程序,运行到写FLASH这部分就和SWIM烧写FLASH冲突了 2.写flash的多种方式及其寄存器配置 Size_OfWord个字节写入flash #define W_rows 9 #define Word_len 240 extern unsigned char flash_buf_word[W_rows*Word_len]@0x9438; gen_word_to_flash(flash_buf_word); void Write_Eflash_Word(unsigned char* target_addr,unsigned char* source_addr)//字模式 { if((target_addr[0]==source_addr[0]) && (target_addr[1]==source_addr[1])&& (target_addr[2]==source_addr[2])&& (target_addr[3]==source_addr[3])) return; FLASH_PUKR =0x56; FLASH_PUKR =0xae; FLASH_CR2 |= 0x40; FLASH_NCR2 &= 0xbf; //enable flash write target_addr[0]=source_addr[0]; target_addr[1]=source_addr[1]; target_addr[2]=source_addr[2]; target_addr[3]=source_addr[3]; FLASH_IAPSR&=~0x02; } void Word_write_in_flash(unsigned char flash_buf[],unsigned char word[],unsigned short Size_OfWord) { unsigned char i; for(i=0;i《Size_OfWord/12;i++) //i=led position { //-------------------------------一次写进flash 12个字节 Write_Eflash_Word(flash_buf+12*i+0, word+i*12); Write_Eflash_Word(flash_buf+12*i+4, word+i*12+4); Write_Eflash_Word(flash_buf+12*i+8, word+i*12+8); } } void gen_word_to_flash(unsigned char flash_buf[]) { unsigned char i=0,j=0; unsigned char word_buf[Word_len]={0}; for(i=0;i《W_rows;i++) //9是行数 { if( (i==0)||(i==W_rows-1) ) { for(j=0;j《LEDs;j++) { word_buf[j*Colors+2]=33; } } else if(i==1) { for(j=0;j《LEDs;j++) { if( (j==14)||(j==15)||(j==16)||(j==19)||(j==20)||(j==21) ) word_buf[j*Colors]=77; } } else if(i==2) { for(j=0;j《LEDs;j++) { if( (j==13)||(j==22)||(j==17)||(j==19) ) word_buf[j*Colors]=77; } } else if(i==3) { for(j=0;j《LEDs;j++) { if( (j==12)||(j==23) ) word_buf[j*Colors]=77; } } else if(i==4) { for(j=0;j《LEDs;j++) { if( (j==13)||(j==22) ) word_buf[j*Colors]=77; } } else if(i==5) { for(j=0;j《LEDs;j++) { if( (j==14)||(j==21) ) word_buf[j*Colors]=77; } } else if(i==6) { for(j=0;j《LEDs;j++) { if( (j==15)||(j==20) ) word_buf[j*Colors]=77; } } else if(i==7) { for(j=0;j《LEDs;j++) { if( (j==16)||(j==18)||(j==17)||(j==19) ) word_buf[j*Colors]=77; } } Word_write_in_flash(flash_buf+i*sizeof(word_buf),word_buf,sizeof(word_buf)); memset(word_buf,0,Word_len); } } 显示flash中的内容 void uart_disp_delay_IDWG(unsigned char dis_buf_0[],unsigned char dis_buf_1[],unsigned char dis_buf_2[],unsigned long ms) { frame_format_gen(dis_buf_1,dis_buf_2); display(dis_buf_0); delay(ms); //TIM4实现延时功能 IWDG_Feed(); //1s喂一次狗别忘 } void all_effects(void) { unsigned int i,n,j,k; unsigned char *p_flash_word[W_rows]={flash_buf_word, flash_buf_word+Word_len, flash_buf_word+Word_len*2, flash_buf_word+Word_len*3, flash_buf_word+Word_len*4, flash_buf_word+Word_len*5, flash_buf_word+Word_len*6, flash_buf_word+Word_len*7, flash_buf_word+Word_len*8}; unsigned char **p_disp; unsigned char dis_buf_n[379]={0}; if(addr==0) { delay(400); //延时很重要。因为SWIM下载程序的同时开始运行程序,运行到写FLASH这部分就和SWIM烧写FLASH冲突了 gen_word_to_flash(flash_buf_word); } IWDG_Init(); //看门狗启动 _asm(“rim”); while(1) { if(addr==0) { //--------------------横幅滚动--------------------------------------------------------- p_disp=p_flash_word; for(i=0;i《LEDs;i++)//不同的多帧 { uart_disp_delay_IDWG(p_disp[1]+Colors*i, p_disp[2]+Colors*i, p_disp[3]+Colors*i, 30); } //-------------------star falling效果--------------------------------------------------------------------- for(i=0;i《LEDs*STMs;i++) //next 帧 { memset(dis_buf_n,0,STMs*Colors*LEDs); for(n=0;n《8;n++) //一帧 { dis_buf_n[(n+i)*Colors+1]=11*(8-n); } uart_disp_delay_IDWG(dis_buf_n, dis_buf_n+LEDs*Colors, dis_buf_n+2*LEDs*Colors, 1); } //-------------------横移闪烁效果--------------------------------------------------------------------- for(i=0;i《20;i++) { if( (i==0) || ((i&1)&&(i》10)) ) { p_disp=p_flash_word; } else if(i==1) { p_disp++; } else if(i==2) { p_disp++; } else { p_disp=p_flash_word+3; } uart_disp_delay_IDWG(p_disp[0], p_disp[1], p_disp[2], 600); } //-------------------视觉暂留效果--------------------------------------------------------------------- p_disp=p_flash_word; for(n=0;n《30;n++) { for(i=0;i《W_rows-3;i++) { if(!(n&1)) p_disp++; else p_disp--; uart_disp_delay_IDWG(p_disp[0]+n*Colors, p_disp[1]+n*Colors, p_disp[2]+n*Colors, 60); } } //*************************************************************************** //从设备 //*************************************************************************** } else { if(data_done_flag) { data_done_flag=0; display(dis_buf_uart1); } } } } |
|
|
|
只有小组成员才能发言,加入小组>>
2516 浏览 0 评论
1095浏览 2评论
705浏览 1评论
458浏览 0评论
200浏览 0评论
342浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-25 16:58 , Processed in 1.991298 second(s), Total 80, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号